Compare commits

..

No commits in common. "master" and "v1.85" have entirely different histories.

370 changed files with 31235 additions and 79807 deletions

View file

@ -1,284 +0,0 @@
name: Picodrive CI
on: [push, pull_request]
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y libsdl1.2-dev libasound2-dev libpng-dev libz-dev
- name: configure
run: DUMP_CONFIG_LOG=1 ./configure
- name: make
run: make -j$(getconf _NPROCESSORS_ONLN)
build-libretro:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: make
run: LDFLAGS=-Wl,--no-undefined make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.libretro
build-gp2x:
runs-on: ubuntu-latest
container: ghcr.io/irixxxx/toolchain-gp2x
permissions:
packages: read
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=gph
make -j$(getconf _NPROCESSORS_ONLN) PLATFORM_MP3=0
make -C platform/gp2x rel VER=$ver
mv PicoDrive_$ver.zip PicoDrive-gph_$ver.zip
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: GP2X
path: PicoDrive-gph_*.zip
build-pandora:
runs-on: ubuntu-latest
container: ghcr.io/irixxxx/toolchain-pandora
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=pandora
make -j$(getconf _NPROCESSORS_ONLN)
make -C platform/pandora rel VER=$ver
mv platform/pandora/PicoDrive_*.pnd .
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: Pandora
path: PicoDrive_*.pnd
build-psp:
runs-on: ubuntu-latest
container: pspdev/pspdev
steps:
- name: build environment
run: |
apk add git gcc g++ zip
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
export CROSS_COMPILE=psp-
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=psp
make -j$(getconf _NPROCESSORS_ONLN)
make -C platform/psp rel VER=$ver
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: PSP
path: PicoDrive_psp_*.zip
build-ps2:
runs-on: ubuntu-latest
container: ps2dev/ps2dev
steps:
- name: build environment
run: |
apk add build-base cmake git zip make
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
export CROSS_COMPILE=mips64r5900el-ps2-elf-
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=ps2
make -j$(getconf _NPROCESSORS_ONLN)
make -C platform/ps2 rel VER=$ver
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: PS2
path: PicoDrive_ps2_*.zip
build-dingux:
runs-on: ubuntu-latest
permissions:
packages: read
container: ghcr.io/irixxxx/toolchain-dingux
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=dingux
make -j$(getconf _NPROCESSORS_ONLN)
mv PicoDrive-dge.zip PicoDrive-dge-$ver.zip
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: Dingux
path: PicoDrive-dge*.zip
build-gcw0:
runs-on: ubuntu-latest
container: ghcr.io/irixxxx/toolchain-opendingux
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=opendingux-gcw0
make -j$(getconf _NPROCESSORS_ONLN)
mv PicoDrive.opk PicoDrive-gcw0-$ver.opk
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: GCW0
path: PicoDrive-gcw0*.opk
build-opendingux:
runs-on: ubuntu-latest
container: ghcr.io/irixxxx/toolchain-opendingux
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=opendingux
make -j$(getconf _NPROCESSORS_ONLN)
mv PicoDrive.opk PicoDrive-opendingux-$ver.opk
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: Opendingux
path: PicoDrive-opendingux*.opk
build-miyoo:
runs-on: ubuntu-latest
permissions:
packages: read
container: ghcr.io/irixxxx/toolchain-miyoo
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=miyoo
make -j$(getconf _NPROCESSORS_ONLN)
mv PicoDrive-miyoo.ipk PicoDrive-miyoo-$ver.ipk
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: Miyoo
path: PicoDrive-miyoo*.ipk
build-retrofw:
runs-on: ubuntu-latest
container: ghcr.io/irixxxx/toolchain-retrofw
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=retrofw
make -j$(getconf _NPROCESSORS_ONLN)
mv PicoDrive.opk PicoDrive-retrofw-$ver.opk
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: RetroFW
path: PicoDrive-retrofw*.opk
build-odbeta-gcw0:
runs-on: ubuntu-latest
container: ghcr.io/irixxxx/toolchain-odbeta-gcw0
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=odbeta
make -j$(getconf _NPROCESSORS_ONLN)
mv PicoDrive.opk PicoDrive-odbeta-gcw0-$ver.opk
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: ODbeta gcw0
path: PicoDrive-odbeta-*.opk
build-odbeta-lepus:
runs-on: ubuntu-latest
container: ghcr.io/irixxxx/toolchain-odbeta-lepus
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=odbeta
make -j$(getconf _NPROCESSORS_ONLN)
mv PicoDrive.opk PicoDrive-odbeta-lepus-$ver.opk
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: ODbeta lepus
path: PicoDrive-odbeta-*.opk
build-odbeta-rg99:
runs-on: ubuntu-latest
container: ghcr.io/irixxxx/toolchain-odbeta-rs90
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: build
run: |
git config --global --add safe.directory $PWD
ver=$(cut -d'"' -f2 platform/common/version.h)-$(git rev-parse --short HEAD)
./configure --platform=odbeta
make -j$(getconf _NPROCESSORS_ONLN)
mv PicoDrive.opk PicoDrive-odbeta-rg99-$ver.opk
- name: artifacts
uses: actions/upload-artifact@v4
with:
name: ODbeta rg99
path: PicoDrive-odbeta-*.opk

View file

@ -1,19 +0,0 @@
name: prepare
on: workflow_call
jobs:
prepare:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: create release
id: create_release
if: ${{ github.ref_type == 'tag' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tag=$(echo ${{ github.ref }} | sed 's:refs/tags/::')
gh release create "$tag" --verify-tag -d -t "$tag" -n "$tag"

28
.gitignore vendored
View file

@ -1,42 +1,18 @@
*.o
*.swp
*.SFO
*.PBP
*.dll
*.lib
*.pdb
*.manifest
*.map
*.exp
*.dylib
*.so
*.a
tags
cscope.out
PicoDrive.map
config.mak
config.log
cpu/musashi/m68kmake
cpu/musashi/m68kops.c
cpu/musashi/m68kops.h
config.cfg
skin
config.cfg
srm/
brm/
mds/
rom/
cfg/
libs/
obj/
.opk_data
.od_data
PicoDrive
picodrive
picodrive_libretro*
PicoDrive*.opk
PicoDrive*.ipk
PicoDrive*.zip
PicoDrive*.elf
pico_int_offs.h
amalgamate
textfilter
.vscode/

14
.gitmodules vendored
View file

@ -1,16 +1,6 @@
[submodule "platform/libpicofe"]
path = platform/libpicofe
url = https://github.com/raytf/libpicofe.git
url = git://notaz.gp2x.de/~notaz/libpicofe.git
[submodule "cpu/cyclone"]
path = cpu/cyclone
url = https://github.com/irixxxx/cyclone68000.git
[submodule "pico/sound/emu2413"]
path = pico/sound/emu2413
url = https://github.com/digital-sound-antiques/emu2413.git
branch = main
[submodule "pico/cd/libchdr"]
path = pico/cd/libchdr
url = https://github.com/irixxxx/libchdr.git
[submodule "platform/common/dr_libs"]
path = platform/common/dr_libs
url = https://github.com/mackron/dr_libs.git
url = git://notaz.gp2x.de/~notaz/cyclone68000.git

62
AUTHORS
View file

@ -1,62 +0,0 @@
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/
irixxxx
improvements to dynamic recompilers, 32X emulation, ARM asm, sound, VDP,
platforms (GPH, PSP, generic linux), added SG-1000 and Game Gear support,
fixed a lot of bugs (and probably added more new bugs), cleaned up stuff,
probably more that I've already forgotten.
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
* Hiroshica for support of japanese Mark-III extended YM2413 sound
* Anyone else I forgot. Let me know if it's you.

487
ChangeLog
View file

@ -1,487 +0,0 @@
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.

384
Makefile
View file

@ -1,10 +1,15 @@
$(LD) ?= $(CC)
TARGET ?= picodrive
ASAN ?= 0
DEBUG ?= 0
CFLAGS += -I$(PWD)
CYCLONE_CC ?= gcc
CYCLONE_CXX ?= g++
TARGET ?= PicoDrive
CFLAGS += -Wall -ggdb -falign-functions=2
CFLAGS += -I.
ifndef DEBUG
CFLAGS += -O2 -DNDEBUG
endif
#CFLAGS += -DEVT_LOG
#CFLAGS += -DDRC_CMP
#cpu_cmp = 1
#drc_debug = 7
#profile = 1
all: config.mak target_
@ -23,70 +28,7 @@ else # NO_CONFIG_MAK
config.mak:
endif
# This is actually needed, believe me - one bit is used as a flag in some tables
# If you really have to disable this, set NO_ALIGN_FUNCTIONS elsewhere.
ifndef NO_ALIGN_FUNCTIONS
CFLAGS += -falign-functions=2
endif
# profiling
pprof ?= 0
gperf ?= 0
ifneq ("$(PLATFORM)", "libretro")
CFLAGS += -Wall -g
ifneq ("$(PLATFORM)", "psp")
ifneq ($(findstring gcc,$(shell $(CC) -v 2>&1)),)
CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS += -Wl,--gc-sections
endif
endif
ifeq "$(ASAN)" "1"
CFLAGS += -fsanitize=address -fsanitize=leak -fsanitize=bounds -fno-omit-frame-pointer -fno-common -O1 -g
LDLIBS += -fsanitize=address -fsanitize=leak -fsanitize=bounds -static-libasan
else
ifeq "$(DEBUG)" "0"
CFLAGS += -O3 -DNDEBUG
else
CFLAGS += -O1
endif
endif
LD = $(CC)
OBJOUT ?= -o
LINKOUT ?= -o
endif
chkCCflag = $(shell n=/dev/null; echo $(1) | tr " " "\n" | while read f; do \
$(CC) $$f -x c -c $$n -o $$n 2>$$n && echo "_$$f" | tr -d _; done)
ifeq ("$(PLATFORM)",$(filter "$(PLATFORM)","gp2x" "opendingux" "rpi1"))
# very small caches, avoid optimization options making the binary much bigger
CFLAGS += -fno-common -finline-limit=42 -fno-unroll-loops -ffast-math
CFLAGS += $(call chkCCflag, -fno-stack-protector)
ifneq ($(call chkCCflag, -fipa-ra),) # gcc >= 5
CFLAGS += $(call chkCCflag, -flto -fipa-pta -fipa-ra)
else
# these improve execution speed on 32bit arm/mips with gcc pre-5 toolchains
CFLAGS += $(call chkCCflag, -fno-caller-saves -fno-guess-branch-probability -fno-regmove)
# very old gcc toolchains may not have these options
CFLAGS += $(call chkCCflag, -fno-tree-loop-if-convert -fipa-pta -fno-ipa-cp)
endif
else
ifneq ($(STATIC_LINKING), 1)
CFLAGS += $(call chkCCflag, -flto)
endif
endif
# revision info from repository if this not a tagged release
ifeq "$(shell git describe --tags --exact-match HEAD 2>/dev/null)" ""
GIT_REVISION ?= -$(shell git rev-parse --short HEAD || echo unknown)
endif
CFLAGS += -DREVISION=\"$(GIT_REVISION)\"
# default settings
use_libchdr ?= 1
ifeq "$(ARCH)" "arm"
use_cyclone ?= 1
use_drz80 ?= 1
@ -97,120 +39,42 @@ asm_memory ?= 1
asm_render ?= 1
asm_ym2612 ?= 1
asm_misc ?= 1
asm_cdpico ?= 1
asm_cdmemory ?= 1
asm_mix ?= 1
asm_32xdraw ?= 1
asm_32xmemory ?= 1
else
else # if not arm
use_fame ?= 1
use_cz80 ?= 1
ifneq (,$(filter x86% i386% i686% mips% aarch% riscv% powerpc% ppc%, $(ARCH)))
use_sh2drc ?= 1
endif
endif
-include Makefile.local
# TODO this should somehow go to the platform directory?
ifneq "$(use_cyclone)" "1"
# due to CPU stop flag access
asm_cdpico = 0
asm_cdmemory = 0
endif
# frontend
ifeq "$(PLATFORM)" "generic"
PicoDrive.zip: $(TARGET)
$(RM) -rf .od_data
mkdir .od_data
cp -r platform/linux/skin .od_data
cp platform/game_def.cfg .od_data
$(STRIP) $< -o .od_data/picodrive
cd .od_data && zip -9 -r ../$@ *
all: PicoDrive.zip
endif
ifeq "$(PLATFORM)" "opendingux"
.od_data: $(TARGET)
$(RM) -rf .od_data
mkdir .od_data
cp -r platform/opendingux/data/. .od_data
cp platform/game_def.cfg .od_data
$(STRIP) $< -o .od_data/picodrive
.PHONY: .od_data
ifneq (,$(filter %__DINGUX__, $(CFLAGS)))
# "legacy" dingux without opk support
PicoDrive-dge.zip: .od_data
rm -f .od_data/default.*.desktop
cd .od_data && zip -9 -r ../$@ *
all: PicoDrive-dge.zip
CFLAGS += -DSDL_SURFACE_SW # some legacy dinguces had bugs in HWSURFACE
else
ifneq (,$(filter %__MIYOO__, $(CFLAGS)))
PicoDrive-miyoo.ipk: .od_data
rm -f .od_data/default.*.desktop .od_data/PicoDrive.dge
gm2xpkg -i platform/miyoo/pkg.cfg
mv picodrive.ipk $@
@gm2xpkg -c platform/miyoo/pkg.cfg >/dev/null 2>&1
all: PicoDrive-miyoo.ipk
else
PicoDrive.opk: .od_data
rm -f .od_data/PicoDrive.dge
mksquashfs .od_data $@ -all-root -noappend -no-exports -no-xattrs
all: PicoDrive.opk
endif
endif
OBJS += platform/opendingux/inputmap.o
use_inputmap ?= 1
# 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
# Stupid renaming occured in latest raspbian...
ifneq (,$(wildcard /opt/vc/lib/libbrcmGLESv2.so))
LDFLAGS += -lbrcmEGL -lbrcmGLESv2
else
LDFLAGS += -lEGL -lGLESv2 # on raspi GLESv1_CM is included in GLESv2
endif
OBJS += platform/linux/emu.o platform/linux/blit.o # FIXME
OBJS += platform/common/plat_sdl.o platform/common/input_sdlkbd.o
OBJS += platform/common/plat_sdl.o
OBJS += platform/libpicofe/plat_sdl.o platform/libpicofe/in_sdl.o
OBJS += platform/libpicofe/linux/plat.o
USE_FRONTEND = 1
endif
ifeq "$(PLATFORM)" "generic"
#ifeq (y,$(shell echo "\#include <GLES/gl.h>" | $(CC) -E -xc - >/dev/null 2>&1 && echo y))
ifeq "$(HAVE_GLES)" "1"
CFLAGS += -DHAVE_GLES
LDFLAGS += -lEGL -lGLESv1_CM
endif
CFLAGS += -DSDL_OVERLAY_2X -DSDL_BUFFER_3X -DSDL_REDRAW_EVT
OBJS += platform/linux/emu.o platform/linux/blit.o # FIXME
ifeq "$(use_inputmap)" "1"
OBJS += platform/common/plat_sdl.o platform/opendingux/inputmap.o
else
OBJS += platform/common/plat_sdl.o platform/common/inputmap_kbd.o
endif
OBJS += platform/libpicofe/plat_sdl.o platform/libpicofe/in_sdl.o
OBJS += platform/libpicofe/linux/plat.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/in_evdev.o
OBJS += platform/libpicofe/linux/fbdev.o
OBJS += platform/libpicofe/linux/xenv.o
OBJS += platform/libpicofe/linux/plat.o
OBJS += platform/libpicofe/pandora/plat.o
USE_FRONTEND = 1
endif
ifeq "$(PLATFORM)" "gp2x"
OBJS += platform/common/arm_utils.o
OBJS += platform/libpicofe/linux/in_evdev.o
OBJS += platform/libpicofe/linux/plat.o
OBJS += platform/libpicofe/gp2x/in_gp2x.o
OBJS += platform/libpicofe/gp2x/soc.o
OBJS += platform/libpicofe/gp2x/soc_mmsp2.o
@ -224,69 +88,22 @@ 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)" "psp"
CFLAGS += -DUSE_BGR565 -G8 # -DLPRINTF_STDIO -DFW15
LDLIBS += -lpspgu -lpspge -lpsppower -lpspaudio -lpspdisplay -lpspaudiocodec
LDLIBS += -lpspctrl
platform/common/main.o: CFLAGS += -Dmain=pico_main
OBJS += platform/psp/plat.o
OBJS += platform/psp/emu.o
OBJS += platform/psp/in_psp.o
OBJS += platform/psp/psp.o
OBJS += platform/psp/asm_utils.o
OBJS += platform/psp/mp3.o
USE_FRONTEND = 1
endif
ifeq "$(PLATFORM)" "ps2"
CFLAGS += -DUSE_BGR555 # -DLOG_TO_FILE
LDLIBS += -lpatches -lgskit -ldmakit -lps2_drivers
OBJS += platform/ps2/plat.o
OBJS += platform/ps2/emu.o
OBJS += platform/ps2/in_ps2.o
USE_FRONTEND = 1
PLATFORM_MP3 = 1
endif
ifeq "$(PLATFORM)" "libretro"
OBJS += platform/libretro/libretro.o
ifneq ($(STATIC_LINKING), 1)
CFLAGS += -DHAVE_ZLIB
OBJS += platform/libretro/libretro-common/formats/png/rpng.o
OBJS += platform/libretro/libretro-common/streams/trans_stream.o
OBJS += platform/libretro/libretro-common/streams/trans_stream_pipe.o
OBJS += platform/libretro/libretro-common/streams/trans_stream_zlib.o
OBJS += platform/libretro/libretro-common/file/file_path_io.o
OBJS += platform/libretro/libretro-common/file/file_path.o
OBJS += platform/libretro/libretro-common/vfs/vfs_implementation.o
OBJS += platform/libretro/libretro-common/time/rtime.o
OBJS += platform/libretro/libretro-common/string/stdstring.o
OBJS += platform/libretro/libretro-common/compat/compat_strcasestr.o
OBJS += platform/libretro/libretro-common/encodings/encoding_utf.o
OBJS += platform/libretro/libretro-common/compat/compat_strl.o
ifeq "$(USE_LIBRETRO_VFS)" "1"
OBJS += platform/libretro/libretro-common/compat/compat_posix_string.o
OBJS += platform/libretro/libretro-common/compat/fopen_utf8.o
OBJS += platform/libretro/libretro-common/streams/file_stream.o
OBJS += platform/libretro/libretro-common/streams/file_stream_transforms.o
endif
endif
ifeq "$(USE_LIBRETRO_VFS)" "1"
OBJS += platform/libretro/libretro-common/memmap/memmap.o
endif
OBJS += platform/libretro.o
endif
ifeq "$(USE_FRONTEND)" "1"
# common
OBJS += platform/common/main.o platform/common/emu.o platform/common/upscale.o \
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
ifneq (,$(filter %HAVE_GLES, $(CFLAGS)))
OBJS += platform/libpicofe/gl.o platform/libpicofe/gl_platform.o
endif
platform/libpicofe/fonts.o platform/libpicofe/linux/in_evdev.o \
platform/libpicofe/linux/plat.o
# libpicofe - sound
OBJS += platform/libpicofe/sndout.o
@ -309,62 +126,19 @@ endif
endif # USE_FRONTEND
ifneq "$(PLATFORM)" "psp"
OBJS += platform/common/mp3.o platform/common/mp3_sync.o
OBJS += platform/common/mp3.o
ifeq "$(PLATFORM_MP3)" "1"
OBJS += platform/common/mp3_helix.o
else ifeq "$(HAVE_LIBAVCODEC)" "1"
OBJS += platform/common/mp3_libavcodec.o
else
#OBJS += platform/common/mp3_minimp3.o
OBJS += platform/common/mp3_drmp3.o
endif
OBJS += platform/common/mp3_dummy.o
endif
ifeq (1,$(use_libchdr))
CFLAGS += -DUSE_LIBCHDR
# chdr
CHDR = pico/cd/libchdr
CHDR_OBJS += $(CHDR)/src/libchdr_chd.o $(CHDR)/src/libchdr_cdrom.o
CHDR_OBJS += $(CHDR)/src/libchdr_flac.o
CHDR_OBJS += $(CHDR)/src/libchdr_bitstream.o $(CHDR)/src/libchdr_huffman.o
LZMA = $(CHDR)/deps/lzma-24.05
LZMA_OBJS += $(LZMA)/src/CpuArch.o $(LZMA)/src/Alloc.o $(LZMA)/src/LzmaEnc.o
LZMA_OBJS += $(LZMA)/src/Sort.o $(LZMA)/src/LzmaDec.o $(LZMA)/src/LzFind.o
LZMA_OBJS += $(LZMA)/src/Delta.o
$(LZMA_OBJS): CFLAGS += -DZ7_ST -Wno-unused
ZSTD = $(CHDR)/deps/zstd-1.5.6/lib
ZSTD_OBJS += $(ZSTD)/common/entropy_common.o $(ZSTD)/common/error_private.o
ZSTD_OBJS += $(ZSTD)/common/fse_decompress.o $(ZSTD)/common/xxhash.o
ZSTD_OBJS += $(ZSTD)/common/zstd_common.o
ZSTD_OBJS += $(ZSTD)/decompress/huf_decompress.o
ifneq (,$(filter x86%, $(ARCH)))
ZSTD_OBJS += $(ZSTD)/decompress/huf_decompress_amd64.o
endif
ZSTD_OBJS += $(ZSTD)/decompress/zstd_ddict.o
ZSTD_OBJS += $(ZSTD)/decompress/zstd_decompress_block.o
ZSTD_OBJS += $(ZSTD)/decompress/zstd_decompress.o
$(ZSTD_OBJS) $(CHDR_OBJS): CFLAGS += -I$(ZSTD) -Wno-unused
OBJS += $(CHDR_OBJS) $(ZSTD_OBJS)
ifneq ($(STATIC_LINKING), 1)
OBJS += $(LZMA_OBJS)
endif
# ouf... prepend includes to overload headers available in the toolchain
CFLAGS := -I$(LZMA)/include -I$(CHDR)/include $(CFLAGS)
endif
ifeq "$(PLATFORM_ZLIB)" "1"
# 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
OBJS += unzip/unzip.o unzip/unzip_stream.o
include platform/common/common.mak
@ -372,66 +146,28 @@ include platform/common/common.mak
OBJS += $(OBJS_COMMON)
CFLAGS += $(addprefix -D,$(DEFINES))
ifneq (,$(findstring sdl,$(OBJS)))
CFLAGS += -DUSE_SDL
endif
ifneq ($(findstring gcc,$(CC)),)
ifneq ($(findstring SunOS,$(shell uname -a)),SunOS)
ifneq ($(findstring clang,$(shell $(CC) -v 2>&1)),)
LDFLAGS += -Wl,-map,$(TARGET).map
else
LDFLAGS += -Wl,-Map=$(TARGET).map
endif
endif
endif
target_: $(TARGET)
clean:
$(RM) $(TARGET) $(OBJS) pico/pico_int_offs.h
$(MAKE) -C cpu/cyclone clean
$(MAKE) -C cpu/musashi clean
$(MAKE) -C tools clean
$(RM) -r .od_data
$(RM) $(TARGET) $(OBJS)
$(TARGET): $(OBJS)
ifeq ($(STATIC_LINKING_LINK), 1)
$(AR) rcs $@ $^
else
$(LD) $(LINKOUT)$@ $^ $(CFLAGS) $(LDFLAGS) $(LDLIBS)
endif
ifeq "$(PLATFORM)" "psp"
PSPSDK ?= $(shell psp-config --pspsdk-path)
TARGET = PicoDrive
PSP_EBOOT_TITLE = Sonic UGC
PSP_EBOOT_ICON = platform/psp/data/icon.png
PSP_EBOOT_PIC1 = platform/psp/skin/background_selector.png
PSP_EBOOT_SND0 = platform/psp/data/SND0.AT3
LIBS += -lpng -lm -lz -lpspgu -lpsppower -lpspaudio -lpsprtc -lpspaudiocodec
EXTRA_TARGETS = EBOOT.PBP
include $(PSPSDK)/lib/build.mak
# TODO image generation
endif
$(CC) -o $@ $(CFLAGS) $^ $(LDFLAGS) $(LDLIBS)
pprof: platform/linux/pprof.c
$(CC) $(CFLAGS) -O2 -ggdb -DPPROF -DPPROF_TOOL -I../../ -I. $^ -o $@ $(LDFLAGS) $(LDLIBS)
$(CC) -O2 -ggdb -DPPROF -DPPROF_TOOL -I../../ -I. $^ -o $@
pico/pico_int_offs.h: tools/mkoffsets.sh
make -C tools/ XCC="$(CC)" XCFLAGS="$(CFLAGS) -UUSE_LIBRETRO_VFS" XPLATFORM="$(platform)"
%.o: %.c
$(CC) -c $(OBJOUT)$@ $< $(CFLAGS)
tools/textfilter: tools/textfilter.c
make -C tools/ textfilter
.s.o:
$(CC) $(CFLAGS) -c $< -o $@
.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
@ -441,47 +177,11 @@ 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
ifeq (1,$(use_sh2drc))
ifneq (,$(findstring -flto,$(CFLAGS)))
# if using the DRC, memory and sh2soc directly use the DRC register for SH2 SR
# to avoid saving and reloading it. However, this collides with the use of LTO.
pico/32x/memory.o: CFLAGS += -fno-lto
pico/32x/sh2soc.o: CFLAGS += -fno-lto
cpu/sh2/compiler.o: CFLAGS += -fno-lto
endif
ifneq (,$(filter mips64%, $(ARCH))$(filter %mips32r2, $(CFLAGS)))
CFLAGS += -DMIPS_USE_SYNCI # mips32r2 clear_cache uses SYNCI instead of a syscall
endif
endif
# 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
ifeq "$(DEBUG)" "0"
ifeq (,$(findstring msvc,$(platform)))
cpu/fame/famec.o: CFLAGS += -g0 -O2 -fno-expensive-optimizations
else
cpu/fame/famec.o: CFLAGS += -Od
endif
endif
tools/make_carthw_c:
make -C tools make_carthw_c
pico/carthw_cfg.c: pico/carthw.cfg tools/make_carthw_c
tools/make_carthw_c $< $@
# preprocessed asm files most probably include the offsets file
$(filter %.S,$(SRCS_COMMON)): pico/pico_int_offs.h
# random deps - TODO remove this and compute dependcies automatically
pico/carthw/svp/compiler.o : cpu/drc/emit_arm.c
cpu/sh2/compiler.o : cpu/drc/emit_arm.c cpu/drc/emit_arm64.c cpu/drc/emit_ppc.c
cpu/sh2/compiler.o : cpu/drc/emit_x86.c cpu/drc/emit_mips.c cpu/drc/emit_riscv.c
# 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/memory.o pico/cd/memory.o pico/32x/memory.o : pico/memory.h
$(shell grep -rl pico_int.h pico) : pico/pico_int.h
# pico/cart.o : pico/carthw_cfg.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/pico_int.h pico/memory.h
cpu/fame/famec.o: cpu/fame/famec.c cpu/fame/famec_opcodes.h
platform/common/menu_pico.o: platform/libpicofe/menu.c

View file

@ -1,23 +1,16 @@
# Makefile for PicoDrive (libretro)
SPACE :=
SPACE := $(SPACE) $(SPACE)
BACKSLASH :=
BACKSLASH := \$(BACKSLASH)
filter_out1 = $(filter-out $(firstword $1),$1)
filter_out2 = $(call filter_out1,$(call filter_out1,$1))
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
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
@ -26,687 +19,136 @@ AS ?= as
CC_AS ?= $(CC)
CFLAGS ?=
#libretro includes
CFLAGS += -I platform/libretro/libretro-common/include
CFLAGS += -I platform/libretro/libretro-common/include/compat
CFLAGS += -I platform/libretro/libretro-common/include/encodings
CFLAGS += -I platform/libretro/libretro-common/include/formats
CFLAGS += -I platform/libretro/libretro-common/include/streams
CFLAGS += -I platform/libretro/libretro-common/include/string
CFLAGS += -I platform/libretro/libretro-common/include/vfs
USE_LIBRETRO_VFS := 1
STATIC_LINKING:= 0
STATIC_LINKING_LINK:= 0
LOW_MEMORY := 0
TARGET_NAME := picodrive
LIBM := -lm
GIT_REVISION ?= -$(shell git rev-parse --short HEAD || echo ???)
CFLAGS += -DREVISION=\"$(GIT_REVISION)\"
fpic :=
ifeq ($(STATIC_LINKING),1)
EXT=a
endif
# Unix
ifeq ($(platform), unix)
EXT ?= so
TARGET := $(TARGET_NAME)_libretro.$(EXT)
fpic := -fPIC
SHARED := -shared
CFLAGS += -DFAMEC_NO_GOTOS
ifneq ($(findstring SunOS,$(shell uname -a)),)
CC=gcc
endif
# x86/x86_64 generic
else ifneq (,$(findstring x86,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so
ARCH := x86
fpic := -fPIC
SHARED := -shared
CFLAGS += -DFAMEC_NO_GOTOS
# AARCH64 generic
else ifeq ($(platform), aarch64)
TARGET := $(TARGET_NAME)_libretro.so
ARCH = aarch64
fpic := -fPIC
SHARED := -shared
CFLAGS += -DFAMEC_NO_GOTOS
# Portable Linux
else ifeq ($(platform), linux-portable)
EXT ?= so
TARGET := $(TARGET_NAME)_libretro.$(EXT)
SHARED := -shared -nostdlib
fpic := -fPIC
LIBM :=
CFLAGS += -DFAMEC_NO_GOTOS
# OS X
else ifeq ($(platform), osx)
EXT ?= dylib
TARGET := $(TARGET_NAME)_libretro.$(EXT)
SHARED := -dynamiclib
fpic := -fPIC
APPLE := 1
ifeq ($(CROSS_COMPILE),1)
TARGET_RULE = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT)
CFLAGS += $(TARGET_RULE)
CPPFLAGS += $(TARGET_RULE)
CXXFLAGS += $(TARGET_RULE)
LDFLAGS += $(TARGET_RULE)
endif
ifndef ($(NOUNIVERSAL))
CFLAGS += $(ARCHFLAGS)
LDFLAGS += $(ARCHFLAGS)
endif
CFLAGS += -DUINT8=uint8_t -DUINT16=uint16_t -DUINT32=uint32_t -DINT8=int8_t -DINT16=int16_t -DINT32=int32_t
else ifeq ($(platform), staticios)
TARGET := $(TARGET_NAME)_libretro_ios.a
APPLE := 1
ifeq ($(IOSSDK),)
IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path)
endif
CC = clang -arch armv7 -arch arm64 -isysroot $(IOSSDK)
CXX = clang++ -arch armv7 -arch arm64 -isysroot $(IOSSDK)
CC_AS = perl ./tools/gas-preprocessor.pl $(CC)
CFLAGS += -marm
CFLAGS += -DIOS
CC += -miphoneos-version-min=8.0
CXX += -miphoneos-version-min=8.0
CC_AS += -miphoneos-version-min=8.0
CFLAGS += -miphoneos-version-min=8.0
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
# iOS
else ifneq (,$(findstring ios,$(platform)))
TARGET := $(TARGET_NAME)_libretro_ios.dylib
SHARED := -dynamiclib
fpic := -fPIC
APPLE := 1
MINVERSION :=
ifeq ($(IOSSDK),)
IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path)
endif
ifeq ($(platform),ios-arm64)
CC = clang -arch arm64 -isysroot $(IOSSDK)
CXX = clang++ -arch arm64 -isysroot $(IOSSDK)
CFLAGS += -marm -DARM -D__aarch64__=1
else
CC = clang -arch armv7 -isysroot $(IOSSDK)
CXX = clang++ -arch armv7 -isysroot $(IOSSDK)
CC_AS = perl ./tools/gas-preprocessor.pl $(CC)
CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -marm
ASFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon
NO_ARM_ASM = 1
endif
CFLAGS += -DIOS
ifeq ($(platform),$(filter $(platform),ios9 ios-arm64))
MINVERSION = -miphoneos-version-min=8.0
else
MINVERSION = -miphoneos-version-min=5.0
endif
CC += $(MINVERSION)
CXX += $(MINVERSION)
CC_AS += $(MINVERSION)
CFLAGS += $(MINVERSION)
# tvOS
else ifeq ($(platform), tvos-arm64)
TARGET := $(TARGET_NAME)_libretro_tvos.dylib
SHARED := -dynamiclib
fpic := -fPIC
APPLE := 1
ifeq ($(IOSSDK),)
IOSSDK := $(shell xcodebuild -version -sdk appletvos Path)
endif
CC_AS = perl ./tools/gas-preprocessor.pl $(CC)
CC = cc -arch arm64 -isysroot $(IOSSDK)
CXX = c++ -arch arm64 -isysroot $(IOSSDK)
CFLAGS += -marm -DARM -D__aarch64__=1
CFLAGS += -DIOS
# Lightweight PS3 Homebrew SDK
else ifneq (,$(filter $(platform), ps3 psl1ght))
TARGET := $(TARGET_NAME)_libretro_$(platform).a
CC = $(PS3DEV)/ppu/bin/ppu-$(COMMONLV)gcc$(EXE_EXT)
AR = $(PS3DEV)/ppu/bin/ppu-$(COMMONLV)ar$(EXE_EXT)
CFLAGS += -DFAMEC_NO_GOTOS -D__PS3__
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
ifeq ($(platform), psl1ght)
FLAGS += -D__PSL1GHT__
endif
# PSP
else ifeq ($(platform), psp1)
ARCH = mipsel
TARGET := $(TARGET_NAME)_libretro_$(platform).a
CC = psp-gcc$(EXE_EXT)
AR = psp-ar$(EXE_EXT)
CFLAGS += -DPSP -G0 -ftracer
CFLAGS += -I$(shell psp-config --pspsdk-path)/include
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
# PS2
else ifeq ($(platform), ps2)
ARCH = mipsel
TARGET := $(TARGET_NAME)_libretro_$(platform).a
CC = mips64r5900el-ps2-elf-gcc$(EXE_EXT)
AR = mips64r5900el-ps2-elf-ar$(EXE_EXT)
CFLAGS += -Wall -DPS2 -D_EE -DUSE_BGR555 -DFAMEC_NO_GOTOS -DRENDER_GSKIT_PS2 -fsingle-precision-constant
CFLAGS += -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ee/include -I$(PS2SDK)/common/include
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
# CTR (3DS)
else ifeq ($(platform), ctr)
TARGET := $(TARGET_NAME)_libretro_$(platform).a
CC = $(DEVKITARM)/bin/arm-none-eabi-gcc$(EXE_EXT)
CXX = $(DEVKITARM)/bin/arm-none-eabi-g++$(EXE_EXT)
AR = $(DEVKITARM)/bin/arm-none-eabi-ar$(EXE_EXT)
CFLAGS += -DARM11 -D_3DS
CFLAGS += -march=armv6k -mtune=mpcore -mfloat-abi=hard -marm -mfpu=vfp
CFLAGS += -Wall -mword-relocations
CFLAGS += -fomit-frame-pointer -ffast-math
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
OBJS += platform/libretro/3ds/3ds_utils.o platform/libretro/3ds/utils.o
# Raspberry Pi
else ifneq (,$(findstring rpi,$(platform)))
CFLAGS += -Wall -mword-relocations
CFLAGS += -fomit-frame-pointer -ffast-math
TARGET := $(TARGET_NAME)_libretro.so
SHARED := -shared
fpic := -fPIC
ifneq (,$(findstring rpi1,$(platform)))
CFLAGS += -marm -mfpu=vfp -mfloat-abi=hard -march=armv6j
else ifneq (,$(findstring rpi2,$(platform)))
CFLAGS += -marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard
else ifneq (,$(findstring rpi3,$(platform)))
CFLAGS += -marm -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard
endif
# Vita
else ifeq ($(platform), vita)
TARGET := $(TARGET_NAME)_libretro_$(platform).a
CC = arm-vita-eabi-gcc$(EXE_EXT)
AR = arm-vita-eabi-ar$(EXE_EXT)
CFLAGS += -DVITA
CFLAGS += -marm -mfpu=neon -mcpu=cortex-a9 -march=armv7-a -mfloat-abi=hard -ffast-math
CFLAGS += -fno-asynchronous-unwind-tables -ftree-vectorize -funroll-loops
CFLAGS += -mword-relocations -fno-unwind-tables
CFLAGS += -fno-optimize-sibling-calls
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
# Xbox 360
else ifeq ($(platform), xenon)
TARGET := $(TARGET_NAME)_libretro_xenon360.a
CC = xenon-gcc$(EXE_EXT)
AR = xenon-ar$(EXE_EXT)
CFLAGS += -D__LIBXENON__ -m32
# Nintendo Game Cube
else ifeq ($(platform), ngc)
TARGET := $(TARGET_NAME)_libretro_$(platform).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
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
# Nintendo Wii
else ifeq ($(platform), wii)
TARGET := $(TARGET_NAME)_libretro_$(platform).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 -ffat-lto-objects
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
# Nintendo Wii U
else ifeq ($(platform), wiiu)
TARGET := $(TARGET_NAME)_libretro_$(platform).a
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
CFLAGS += -DGEKKO -DWIIU -DHW_RVL -DHW_WUP -mwup -mcpu=750 -meabi -mhard-float
STATIC_LINKING = 1
STATIC_LINKING_LINK = 1
# Nintendo Switch (libtransistor)
else ifeq ($(platform), switch)
TARGET := $(TARGET_NAME)_libretro_$(platform).a
include $(LIBTRANSISTOR_HOME)/libtransistor.mk
STATIC_LINKING=1
STATIC_LINKING_LINK = 1
# Nintendo Switch (libnx)
else ifeq ($(platform), libnx)
include $(DEVKITPRO)/libnx/switch_rules
TARGET := $(TARGET_NAME)_libretro_$(platform).a
CFLAGS += -O3 -fomit-frame-pointer -ffast-math -I$(DEVKITPRO)/libnx/include/ -fPIE -Wl,--allow-multiple-definition
CFLAGS += -specs=$(DEVKITPRO)/libnx/switch.specs
CFLAGS += -D__SWITCH__ -DHAVE_LIBNX
CFLAGS += -DARM -D__aarch64__=1 -march=armv8-a -mtune=cortex-a57 -mtp=soft -ffast-math -mcpu=cortex-a57+crc+fp+simd -ffunction-sections
CFLAGS += -Ifrontend/switch -ftree-vectorize
STATIC_LINKING=1
STATIC_LINKING_LINK = 1
# QNX
else ifeq ($(platform), qnx)
ARCH = arm
TARGET := $(TARGET_NAME)_libretro_$(platform).so
fpic := -fPIC
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
# (armv7 a7, hard point, neon based) ###
# NESC, SNESC, C64 mini
else ifeq ($(platform), classic_armv7_a7)
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC
SHARED := -shared -Wl,--no-undefined,-Bsymbolic
CFLAGS += -Ofast \
-flto=4 -fuse-linker-plugin \
-fdata-sections -ffunction-sections -Wl,--gc-sections \
-fno-stack-protector -fno-ident -fomit-frame-pointer \
-falign-functions=1 -falign-jumps=1 -falign-loops=1 \
-fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \
-fmerge-all-constants -fno-math-errno \
-marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard
CXXFLAGS += $(CFLAGS)
CPPFLAGS += $(CFLAGS)
ASFLAGS += $(CFLAGS)
HAVE_NEON = 1
BUILTIN_GPU = neon
ifeq ($(shell echo `$(CC) -dumpversion` "< 4.9" | bc -l), 1)
CFLAGS += -march=armv7-a
else
CFLAGS += -march=armv7ve
# If gcc is 5.0 or later
ifeq ($(shell echo `$(CC) -dumpversion` ">= 5" | bc -l), 1)
LDFLAGS += -static-libgcc -static-libstdc++
endif
endif
# (armv8 a35, hard point, neon based) ###
# Playstation Classic
else ifeq ($(platform), classic_armv8_a35)
TARGET := $(TARGET_NAME)_libretro.so
fpic := -fPIC
SHARED := -shared -Wl,--no-undefined,-Bsymbolic
CFLAGS += -Ofast \
-flto -fuse-linker-plugin \
-fdata-sections -ffunction-sections -Wl,--gc-sections \
-fno-stack-protector -fno-ident -fomit-frame-pointer \
-falign-functions=1 -falign-jumps=1 -falign-loops=1 \
-fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \
-fmerge-all-constants -fno-math-errno -fno-strict-aliasing \
-marm -mtune=cortex-a35 -mfpu=neon-fp-armv8 -mfloat-abi=hard
CXXFLAGS += $(CFLAGS)
CPPFLAGS += $(CFLAGS)
ASFLAGS += $(CFLAGS)
HAVE_NEON = 1
BUILTIN_GPU = neon
CFLAGS += -march=armv8-a
LDFLAGS += -static-libgcc -static-libstdc++
#######################################
# ARM-64
else ifeq ($(platform), arm64)
EXT ?= so
TARGET := $(TARGET_NAME)_libretro.$(EXT)
ARCH = aarch64
fpic := -fPIC
SHARED := -shared
CFLAGS += -DFAMEC_NO_GOTOS
# AARCH64 generic
else ifeq ($(platform), aarch64)
TARGET := $(TARGET_NAME)_libretro.so
ARCH = aarch64
fpic := -fPIC
SHARED := -shared
CFLAGS += -DFAMEC_NO_GOTOS
# ARM
else ifneq (,$(findstring armv,$(platform)))
TARGET := $(TARGET_NAME)_libretro.so
SHARED := -shared -Wl,--no-undefined,-Bsymbolic
fpic := -fPIC
ifneq (,$(findstring cortexa5,$(platform)))
CFLAGS += -marm -mcpu=cortex-a5
ASFLAGS += -mcpu=cortex-a5
else 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
else ifneq (,$(findstring cortexa15a7,$(platform)))
CFLAGS += -marm -mcpu=cortex-a15.cortex-a7
ASFLAGS += -mcpu=cortex-a15.cortex-a7
else
CFLAGS += -marm
endif
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
ifeq (,$(findstring armasm,$(platform)))
NO_ARM_ASM = 1
endif
# Emscripten
else ifeq ($(platform), emscripten)
TARGET := $(TARGET_NAME)_libretro_$(platform).bc
ARCH = unknown
STATIC_LINKING = 1
# RS90
else ifeq ($(platform), rs90)
TARGET := $(TARGET_NAME)_libretro.so
ifeq (,$(shell command -v $(RS90_PREFIX)mipsel-rs90-linux-uclibc-gcc 2>/dev/null))
# locate the toolchain for buildbot if it isn't in path or prefix not set
RS90_PREFIX = /opt/rs90-toolchain/usr/bin/
endif
CC = $(RS90_PREFIX)mipsel-linux-gcc
AR = $(RS90_PREFIX)mipsel-linux-ar
SHARED := -shared -nostdlib
fpic := -fPIC
LIBM :=
CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32 -D__GCW0__
# clear_cache uses SYNCI instead of a syscall
CFLAGS += -DMIPS_USE_SYNCI
LOW_MEMORY = 1
# GCW0
else ifeq ($(platform), gcw0)
TARGET := $(TARGET_NAME)_libretro.so
ifeq (,$(shell command -v $(GCW0_PREFIX)mipsel-gcw0-linux-uclibc-gcc 2>/dev/null))
# locate the toolchain for buildbot if it isn't in path or prefix not set
GCW0_PREFIX = /opt/gcw0-toolchain/usr/bin/
endif
CC = $(GCW0_PREFIX)mipsel-linux-gcc
AR = $(GCW0_PREFIX)mipsel-linux-ar
SHARED := -shared -nostdlib
fpic := -fPIC
LIBM :=
CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32r2 -mhard-float -D__GCW0__
# clear_cache uses SYNCI instead of a syscall
CFLAGS += -DMIPS_USE_SYNCI
# RETROFW
else ifeq ($(platform), retrofw)
TARGET := $(TARGET_NAME)_libretro.so
ifeq (,$(shell command -v $(GCW0_PREFIX)mipsel-gcw0-linux-uclibc-gcc 2>/dev/null))
# locate the toolchain for buildbot if it isn't in path or prefix not set
GCW0_PREFIX = /opt/retrofw-toolchain/usr/bin/
endif
CC = $(GCW0_PREFIX)mipsel-linux-gcc
AR = $(GCW0_PREFIX)mipsel-linux-ar
SHARED := -shared -nostdlib
fpic := -fPIC
LIBM :=
CFLAGS += -fomit-frame-pointer -ffast-math -march=mips32 -mtune=mips32 -mhard-float -D__GCW0__
# clear_cache uses SYNCI instead of a syscall
CFLAGS += -DMIPS_USE_SYNCI
# MIYOO
else ifeq ($(platform), miyoo)
TARGET := $(TARGET_NAME)_libretro.so
CC = /opt/miyoo/usr/bin/arm-linux-gcc
AR = /opt/miyoo/usr/bin/arm-linux-ar
SHARED := -shared -nostdlib
fpic := -fPIC
LIBM :=
CFLAGS += -fomit-frame-pointer -ffast-math -march=armv5te -mtune=arm926ej-s -D__GCW0__
HAVE_ARMv6 = 0
LOW_MEMORY = 1
# Windows MSVC 2017 all architectures
else ifneq (,$(findstring windows_msvc2017,$(platform)))
NO_GCC := 1
PlatformSuffix = $(subst windows_msvc2017_,,$(platform))
ifneq (,$(findstring desktop,$(PlatformSuffix)))
WinPartition = desktop
MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP -FS
LDFLAGS += -MANIFEST -LTCG:incremental -NXCOMPAT -DYNAMICBASE -DEBUG -OPT:REF -INCREMENTAL:NO -SUBSYSTEM:WINDOWS -MANIFESTUAC:"level='asInvoker' uiAccess='false'" -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1
LDLIBS += kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib
else ifneq (,$(findstring uwp,$(PlatformSuffix)))
WinPartition = uwp
MSVC2017CompileFlags = -DWINAPI_FAMILY=WINAPI_FAMILY_APP -D_WINDLL -D_UNICODE -DUNICODE -D__WRL_NO_DEFAULT_LIB__ -EHsc -FS
LDFLAGS += -APPCONTAINER -NXCOMPAT -DYNAMICBASE -MANIFEST:NO -LTCG -OPT:REF -SUBSYSTEM:CONSOLE -MANIFESTUAC:NO -OPT:ICF -ERRORREPORT:PROMPT -NOLOGO -TLBID:1 -DEBUG:FULL -WINMD:NO
LDLIBS += WindowsApp.lib
endif
ARCH = x86_64
SHARED :=
LIBM :=
NO_ALIGN_FUNCTIONS = 1
CFLAGS += -DHAVE_VSNPRINTF
CFLAGS += $(MSVC2017CompileFlags)
CXXFLAGS += $(MSVC2017CompileFlags)
TargetArchMoniker = $(subst $(WinPartition)_,,$(PlatformSuffix))
CC = cl.exe
CXX = cl.exe
LD = link.exe
reg_query = $(call filter_out2,$(subst $2,,$(shell reg query "$2" -v "$1" 2>nul)))
fix_path = $(subst $(SPACE),\ ,$(subst \,/,$1))
ProgramFiles86w := $(shell cmd //c "echo %PROGRAMFILES(x86)%")
ProgramFiles86 := $(shell cygpath "$(ProgramFiles86w)")
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0)
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0)
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0)
WindowsSdkDir ?= $(call reg_query,InstallationFolder,HKEY_CURRENT_USER\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0)
WindowsSdkDir := $(WindowsSdkDir)
WindowsSDKVersion ?= $(firstword $(foreach folder,$(subst $(subst \,/,$(WindowsSdkDir)Include/),,$(wildcard $(call fix_path,$(WindowsSdkDir)Include\*))),$(if $(wildcard $(call fix_path,$(WindowsSdkDir)Include/$(folder)/um/Windows.h)),$(folder),)))$(BACKSLASH)
WindowsSDKVersion := $(WindowsSDKVersion)
VsInstallBuildTools = $(ProgramFiles86)/Microsoft Visual Studio/2017/BuildTools
VsInstallEnterprise = $(ProgramFiles86)/Microsoft Visual Studio/2017/Enterprise
VsInstallProfessional = $(ProgramFiles86)/Microsoft Visual Studio/2017/Professional
VsInstallCommunity = $(ProgramFiles86)/Microsoft Visual Studio/2017/Community
VsInstallRoot ?= $(shell if [ -d "$(VsInstallBuildTools)" ]; then echo "$(VsInstallBuildTools)"; fi)
ifeq ($(VsInstallRoot), )
VsInstallRoot = $(shell if [ -d "$(VsInstallEnterprise)" ]; then echo "$(VsInstallEnterprise)"; fi)
endif
ifeq ($(VsInstallRoot), )
VsInstallRoot = $(shell if [ -d "$(VsInstallProfessional)" ]; then echo "$(VsInstallProfessional)"; fi)
endif
ifeq ($(VsInstallRoot), )
VsInstallRoot = $(shell if [ -d "$(VsInstallCommunity)" ]; then echo "$(VsInstallCommunity)"; fi)
endif
VsInstallRoot := $(VsInstallRoot)
VcCompilerToolsVer := $(shell cat "$(VsInstallRoot)/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" | grep -o '[0-9\.]*')
VcCompilerToolsDir := $(VsInstallRoot)/VC/Tools/MSVC/$(VcCompilerToolsVer)
WindowsSDKSharedIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\shared")
WindowsSDKUCRTIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\ucrt")
WindowsSDKUMIncludeDir := $(shell cygpath -w "$(WindowsSdkDir)\Include\$(WindowsSDKVersion)\um")
WindowsSDKUCRTLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\ucrt\$(TargetArchMoniker)")
WindowsSDKUMLibDir := $(shell cygpath -w "$(WindowsSdkDir)\Lib\$(WindowsSDKVersion)\um\$(TargetArchMoniker)")
# For some reason the HostX86 compiler doesn't like compiling for x64
# ("no such file" opening a shared library), and vice-versa.
# Work around it for now by using the strictly x86 compiler for x86, and x64 for x64.
# NOTE: What about ARM?
ifneq (,$(findstring x64,$(TargetArchMoniker)))
VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX64
else
VCCompilerToolsBinDir := $(VcCompilerToolsDir)\bin\HostX86
endif
PATH := $(shell IFS=$$'\n'; cygpath "$(VCCompilerToolsBinDir)/$(TargetArchMoniker)"):$(PATH)
PATH := $(PATH):$(shell IFS=$$'\n'; cygpath "$(VsInstallRoot)/Common7/IDE")
INCLUDE := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/include")
LIB := $(shell IFS=$$'\n'; cygpath -w "$(VcCompilerToolsDir)/lib/$(TargetArchMoniker)")
ifneq (,$(findstring uwp,$(PlatformSuffix)))
LIB := $(shell IFS=$$'\n'; cygpath -w "$(LIB)/store")
endif
export INCLUDE := $(INCLUDE);$(WindowsSDKSharedIncludeDir);$(WindowsSDKUCRTIncludeDir);$(WindowsSDKUMIncludeDir)
export LIB := $(LIB);$(WindowsSDKUCRTLibDir);$(WindowsSDKUMLibDir)
TARGET := $(TARGET_NAME)_libretro.dll
PSS_STYLE :=2
LDFLAGS += -DLL
# Windows
else
TARGET := $(TARGET_NAME)_libretro.dll
CC ?= gcc
fpic := -fPIC
SHARED := -shared -static-libgcc -static-libstdc++
CFLAGS += -D__WIN32__ -D__WIN32_LIBRETRO__
endif
CFLAGS += -D__LIBRETRO__
ifeq ($(USE_LIBRETRO_VFS),1)
CFLAGS += -DUSE_LIBRETRO_VFS
endif
ifeq ($(LOW_MEMORY), 1)
CFLAGS += -DLOW_MEMORY
endif
ifeq ($(NO_ARM_ASM),1)
use_cyclone = 0
use_fame = 1
use_drz80 = 0
use_cz80 = 1
use_svpdrc = 0
asm_memory = 0
asm_render = 0
asm_ym2612 = 0
asm_misc = 0
asm_cdpico = 0
asm_cdmemory = 0
asm_mix = 0
asm_32xdraw = 0
asm_32xmemory = 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)
CXX = clang++ -arch armv7 -isysroot $(IOSSDK)
CC_AS = perl ./tools/gas-preprocessor.pl $(CC)
CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -marm
ASFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon
CFLAGS += -DIOS
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)_retro.dll
CC = gcc
LD_FLAGS := -fPIC
SHARED := -shared -static-libgcc -static-libstdc++
CFLAGS += -D__WIN32__ -D__WIN32_LIBRETRO__
endif
ifeq ($(APPLE),1)
# turn off DRCs on Apple OSes. It needs signing and notarizing on the
# later versions, which picodrive isn't supporting right now.
use_sh2drc = 0
use_svpdrc = 0
endif
CFLAGS += $(fpic)
ifeq ($(findstring Haiku,$(shell uname -a)),)
LDLIBS += $(LIBM)
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) $(fpic)
LDFLAGS += $(SHARED)
ifeq ($(ARCH),)
ARCH = $(shell $(CC) -dumpmachine | awk -F '-' '{print $$1}')
endif
PLATFORM = libretro
NO_CONFIG_MAK = yes
OBJOUT = -o
LINKOUT = -o
ifneq (,$(findstring msvc,$(platform)))
CFLAGS += -wd4702 -wd4711 -wd4202 -wd4101
endif
ifeq ($(DEBUG), 1)
ifneq (,$(findstring msvc,$(platform)))
ifeq ($(STATIC_LINKING),1)
CFLAGS += -MTd
CXXFLAGS += -MTd
else
CFLAGS += -MDd
CXXFLAGS += -MDd
endif
CFLAGS += -Od -Zi -DDEBUG -D_DEBUG
CXXFLAGS += -Od -Zi -DDEBUG -D_DEBUG
else
CFLAGS += -O0 -g -DDEBUG
CXXFLAGS += -O0 -g -DDEBUG
endif
else
ifneq (,$(findstring msvc,$(platform)))
ifeq ($(STATIC_LINKING),1)
CFLAGS += -MT
CXXFLAGS += -MT
else
CFLAGS += -MD
CXXFLAGS += -MD
endif
CFLAGS += -O2 -DNDEBUG
CXXFLAGS += -O2 -DNDEBUG
else
CFLAGS += -O3 -DNDEBUG
CXXFLAGS += -O3 -DNDEBUG
endif
endif
ifneq (,$(findstring msvc,$(platform)))
OBJOUT = -Fo
LINKOUT = -out:
ifeq ($(STATIC_LINKING),1)
LD ?= lib.exe
STATIC_LINKING=0
else
LD = link.exe
endif
else
LD = $(CC)
endif
PLATFORM_ZLIB ?= 1
include Makefile
ifeq ($(platform), osx)
pico/cd/libchdr/src/libchdr_chd.o: CFLAGS += -D__MACTYPES__=1
endif

View file

@ -1,55 +0,0 @@
# Sonic's UGC for PSP
A fork of PicoDrive for PSP, skinned to look like Sonic's Ultimate Genesis Collection
### Why?
In 2019 (when i originally had this idea) i had just gotten a PSP, and in 2016-2020 i had a copy of Sonic's UGC on the Xbox 360, i knew that the PSP was very much powerful enough to run the same library of games, and this was on the back of my head until August of 2024, when i finally gained enough skill to make this into a reality.
**Fun Fact** - I did make a **terrible** version of this idea in 2019 with my limited brain, which i still have archived today, (i stretched the SUGC logo to fit on the PBP, changed the background which made the game list almost unreadable, and a few other horrible hacks), but, it didn't involve any source code. This time i'm doing it for real, redesigning the UI and open sourcing all of it
### Downloads
Soon!
### To-do List
| Done | Feature | Progress |
| ------- | --------------------- | -------- |
| ✅ (M1) | ISO Support | 100% |
| ✅ (M1) | Game List | 100% |
| ✅ (M2) | Title Screen | 100% |
| ✅ (M2) | Backgrounds | 100% |
| ✅ (M2) | SRAM in SAVEDATA | 100% |
| ✳️ (M3) | Bunken Tech Fontmap | 100% |
| ✳️ (M3) | Background Theme | 35% |
| ❌ (M4) | ROM Selector UI | 0% |
| ❌ (M5) | ROM Boxart UI | 0% |
| ❌ (M6) | Rating System | 0% |
| ❓ (V1) | Customizer Tool | 0% |
### Q&A
**Q: Will you make this for the European version of Sonic's UGC (Sega Mega Drive Ultimate Collection // SEGA MDUC)?**
A: Originally i wasn't going to, but after making a separate branch to do it, i'm definitely going to release it. Up-to-date Development builds will ALWAYS be based on SUGC though.
**Q: Will you make a PS2 Port? It looks really similar to the PSP version!**
A: Never. I haven't owned a PS2 since 2013 (when i was a fucking baby) and don't plan to.
**Q: How can i add more games?**
A: Download or compile the Memory Stick version, go to or create the "rom" directory and add your games there, the file format doesn't matter
**Q: How do i compile on Windows?**
A: Not supported. I haven't used Windows as my daily OS since 2021 and have no plans to go back. Modern Windows is terrible and i have no reason to switch back (the biggest hurdle was Camtasia, which i finally stopped using after 6 years). Just use a Linux VM if you can't make the switch
**Q: Does this work on PS Vita?**
A: Yes, just use Adrenaline and you're good, both the ISO and Memory Stick versions should work with no problem.
**Q: Does this work on PPSSPP?**
A: Absolutely! I used PPSSPP for testing the dev builds and it works flawlessly, but if you're gonna emulate SEGA Genesis games on an emulator, just use a normal Sega Genesis emulator, this is largely intended for people who own a PSP or PS Vita console.
**Q: How did you get an uncompressed version of the SUGC Intro and Soundtrack**
A: I ripped them myself from the Xbox 360 and PS3 version, just extract the files from the ISO and you should be good. ([Intro Video (X360)](https://dl.raythefox.pw/Projects/Sonic%27s%20UGC%20for%20PSP/Assets/SGC2_ATTRACT.wmv) - [Background Theme (Retro Dreams) (X360)](https://dl.raythefox.pw/Projects/Sonic%27s%20UGC%20for%20PSP/Assets/retro_dreams.xma) - [Background Video (X360)](https://dl.raythefox.pw/Projects/Sonic%27s%20UGC%20for%20PSP/Assets/MAIN0001.wmv) - [SUGC Logo (PS3)](https://dl.raythefox.pw/Projects/Sonic%27s%20UGC%20for%20PSP/Assets/SUGC_LOGO.PNG) - [SMDUC Logo (PS3)](https://dl.raythefox.pw/Projects/Sonic%27s%20UGC%20for%20PSP/Assets/SMDUC_LOGO.PNG) - [XMB BGM (PS3)](https://dl.raythefox.pw/Projects/Sonic%27s%20UGC%20for%20PSP/Assets/SND0.AT3) - [XMB BGM (PS3, converted to WAV)](https://dl.raythefox.pw/Projects/Sonic%27s%20UGC%20for%20PSP/Assets/SND0.wav) - [XMB BGM (PS3, converted to MP3)](https://dl.raythefox.pw/Projects/Sonic%27s%20UGC%20for%20PSP/Assets/SND0.mp3))
**Q: How did you figure out this really confusing source code?**
A: I admit that the PicoDrive source code is *almost* unreadable, and i definitely wouldn't recommend it to a beginner, but even if you are total trash at C code like i am, if you know where to look, it's not that hard, 99% of the changes were in the UI and the PSP-specific code, not on the emulator itself, i'm pretty sure it's possible to port this to Windows/Linux/PS2, but i have no desire in doing it myself, i can provide all of the design files, [my DMs are always open](https://raythefox.pw), message me and i'll be glad to help.

307
configure vendored
View file

@ -10,63 +10,53 @@ rm -f config.log
compile_object()
{
c="$CC $MFLAGS $CFLAGS -c $TMPC -o $TMPO $@"
c="$CC $CFLAGS -c $TMPC -o $TMPO $@"
echo $c >> config.log
$c >> config.log 2>&1
}
compile_binary()
{
c="$CC $MFLAGS $CFLAGS $TMPC -o $TMPB $LDFLAGS $@ $SYSLIBS"
c="$CC $CFLAGS $TMPC -o $TMPB $LDFLAGS $@"
echo $c >> config.log
$c >> config.log 2>&1
}
check_option()
{
echo 'void test(void) { }' >$TMPC
compile_object $1 || return 1
return 0
}
check_define()
{
$CC -E -dD $MFLAGS $CFLAGS pico/arm_features.h | grep -q "define[ ]*$1" || return 1
$CC -E -dD $CFLAGS pico/arm_features.h | grep -q $1 || return 1
return 0
}
# setting options to "yes" or "no" will make that choice default,
# "" means "autodetect".
# TODO this is annoyingly messy. should have platform and device
platform_list="generic pandora gph dingux retrofw opendingux[-gcw0] odbeta[-gcw0] miyoo rpi1 rpi2 ps2 psp"
platform_list="generic pandora gp2x"
platform="generic"
sound_driver_list="oss alsa sdl"
sound_drivers=""
have_armv5=""
have_armv6=""
have_armv7=""
have_arm_oabi=""
have_arm_neon=""
have_libavcodec=""
have_libchdr=""
have_gles="no"
need_sdl="no"
need_zlib="no"
need_xlib="no"
# these are for known platforms
optimize_cortexa8="no"
optimize_arm926ej="no"
optimize_arm920="no"
# hardcoded stuff
CC="${CC-${CROSS_COMPILE}gcc}"
CXX="${CXX-${CROSS_COMPILE}g++}"
AS="${AS-${CROSS_COMPILE}as}"
STRIP="${STRIP-${CROSS_COMPILE}strip}"
LD="${LD-${CROSS_COMPILE}gcc}" # Use better gcc for linking
SYSROOT=`$CC $CFLAGS $LDFLAGS --print-sysroot 2> /dev/null || true`
MAIN_LDLIBS="$LDLIBS -lm"
config_mak="config.mak"
fail()
{
echo "$@"
if test -n "$DUMP_CONFIG_LOG"; then cat config.log; fi
exit 1
}
@ -74,91 +64,23 @@ fail()
set_platform()
{
platform=$1
CFLAGS="$CFLAGS -D__`echo ${platform%-*} | tr '[a-z]' '[A-Z]'`__"
case "$platform" in
rpi1)
MFLAGS="-mcpu=arm1176jzf-s -mfpu=vfp"
have_gles="yes"
;;
rpi2)
MFLAGS="-mcpu=cortex-a7 -mfpu=neon"
have_gles="yes"
;;
generic)
MFLAGS=""
;;
dingux)
# dingoo a320, ritmix rzx-50, the like. all have Ingenic MIPS cpu <= JZ4755
sound_drivers="sdl"
# use static linking since the lib situation is ... let's say vague
#LDFLAGS="$LDFLAGS -static"
# uses a pre-gcw0 version of opendingux
MFLAGS="-march=mips32 -msoft-float"
platform="opendingux"
;;
retrofw)
# devices using retrofw. AFAIK all have Ingenic MIPS JZ4760 with fpu
sound_drivers="sdl"
# uses it's own modified version of opendingux
MFLAGS="-march=mips32"
platform="opendingux"
;;
opendingux | opendingux-gcw0)
# more modern devices using opendingux, with Ingenic MIPS JZ4770 or newer
sound_drivers="sdl"
# mostly based on opendingux for gcw0
CFLAGS="$CFLAGS -D__OPENDINGUX__"
[ "${platform#*gcw0}" = "" ] && CFLAGS="$CFLAGS -D__GCW0__"
MFLAGS="-march=mips32r2"
platform="opendingux"
;;
miyoo)
# Miyoo BittBoy, PocketGO 1, PowKiddy V90/Q90 with Allwinner F1C100s
sound_drivers="sdl"
CFLAGS="$CFLAGS -D__OPENDINGUX__"
MFLAGS="-mcpu=arm926ej-s -marm"
platform="opendingux"
;;
odbeta | odbeta-gcw0)
# various devices with opendingux beta, arch flags from toolchain default
sound_drivers="sdl"
CFLAGS="$CFLAGS -D__OPENDINGUX__"
[ "${platform#*gcw0}" = "" ] && CFLAGS="$CFLAGS -D__GCW0__"
MFLAGS="" # toolchains are arch specific
platform="opendingux"
;;
pandora)
sound_drivers="oss alsa"
have_libavcodec="yes"
MFLAGS="-mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp"
optimize_cortexa8="yes"
have_arm_neon="yes"
;;
gph)
gp2x)
sound_drivers="oss"
# compile for OABI if toolchain provides it (faster code on caanoo)
have_arm_oabi="yes"
# always use static linking, since caanoo doesn't have OABI libs. Moreover,
# dynamic linking slows Wiz 1-10%, and libm on F100 isn't compatible
LDFLAGS="$LDFLAGS -static"
# unified binary for all of them. picodrive detects device type for itself.
optimize_arm920="yes"
CFLAGS="$CFLAGS -D__GP2X__"
# add -mfpu=fpa to select correct parameter passing for -msoft-float :-/
MFLAGS="-mcpu=arm920t -mfloat-abi=soft -mfpu=fpa"
platform="gp2x"
;;
psp)
# use newlib
SYSLIBS="-lc -lpspuser -lpspkernel"
MFLAGS="-march=allegrex"
ARCH=mipsel
;;
ps2)
# use newlib
SYSLIBS=""
MFLAGS=""
ARCH=mips64r5900el
ASFLAGS="$ASFLAGS -G0 -call_shared"
CFLAGS="$CFLAGS -D_EE -G0 -I${PS2SDK}/ee/include -I${PS2SDK}/common/include -I${PS2DEV}/gsKit/include -I${PS2SDK}/ports/include"
LDFLAGS="$LDFLAGS -Wl,-zmax-page-size=128 -T${PS2SDK}/ee/startup/linkfile -L${PS2SDK}/ee/lib -L${PS2DEV}/gsKit/lib -L${PS2SDK}/ports/lib"
if [ "$CROSS_COMPILE" = "arm-linux-" ]; then
# still using static, dynamic linking slows Wiz 1-10%
# also libm on F100 is not compatible
MAIN_LDLIBS="$MAIN_LDLIBS -static"
fi
;;
*)
fail "unsupported platform: $platform"
@ -175,12 +97,6 @@ for opt do
;;
--sound-drivers=*) sound_drivers="$optarg"
;;
--with-libavcodec=*) have_libavcodec="$optarg"
;;
--with-sdl-gles=*) have_gles="$optarg"
;;
--with-zlib=*) need_zlib="$optarg"
;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@ -193,11 +109,8 @@ if [ "$show_help" = "yes" ]; then
echo " available: $platform_list"
echo " --sound-drivers=LIST sound output drivers [guessed]"
echo " available: $sound_driver_list"
echo " --with-libavcodec=yes|no use libavcodec for mp3 decoding"
echo " --with-sdl-gles=yes|no enable GLES usage for SDL"
echo " --with-zlib=yes|no use internal zlib"
echo "influential environment variables:"
echo " CROSS_COMPILE CC CXX AS STRIP CFLAGS ASFLAGS LDFLAGS LDLIBS"
echo " CROSS_COMPILE CC CXX AS CFLAGS ASFLAGS LDFLAGS LDLIBS"
exit 1
fi
@ -220,22 +133,34 @@ fi
# fi
#fi
if [ -z "$ARCH" ]; then
ARCH=`$CC $MFLAGS $CFLAGS -dumpmachine | awk -F '-' '{print $1}'`
# basic compiler test
cat > $TMPC <<EOF
int main(void) { return 0; }
EOF
if ! compile_binary; then
fail "compiler test failed, please check config.log"
fi
if [ -z "$ARCH" ]; then
ARCH=`$CC -dumpmachine | awk -F '-' '{print $1}'`
fi
# CPU/ABI stuff first, else compile test may fail
case "$ARCH" in
arm64*)
;;
arm*)
# ARM stuff
ARCH="arm"
# OABI/EABI selection
if [ "$have_arm_oabi" = "yes" ] && check_option -mabi=apcs-gnu; then
echo "$CFLAGS" | grep -q -- '-mabi=' || MFLAGS="$MFLAGS -mabi=apcs-gnu"
echo "$CFLAGS" | grep -q -- '-m\(no-\)*thumb-interwork' || CFLAGS="$CFLAGS -mno-thumb-interwork"
if [ "$optimize_cortexa8" = "yes" ]; then
CFLAGS="$CFLAGS -mcpu=cortex-a8 -mtune=cortex-a8"
ASFLAGS="$ASFLAGS -mcpu=cortex-a8"
fi
if [ "$optimize_arm926ej" = "yes" ]; then
CFLAGS="$CFLAGS -mcpu=arm926ej-s -mtune=arm926ej-s"
ASFLAGS="$ASFLAGS -mcpu=arm926ej-s -mfloat-abi=softfp"
fi
if [ "$optimize_arm920" = "yes" ]; then
CFLAGS="$CFLAGS -mcpu=arm920t -mtune=arm920t"
ASFLAGS="$ASFLAGS -mcpu=arm920t -mfloat-abi=soft"
fi
if [ "x$have_arm_neon" = "x" ]; then
@ -259,14 +184,27 @@ arm*)
have_armv5=`check_define HAVE_ARMV5 && echo yes` || true
fi
# automatically set mfpu and mfloat-abi if they are not set
if [ "$have_arm_neon" = "yes" ]; then
fpu="neon"
elif [ "$have_armv6" = "yes" ]; then
fpu="vfp"
fi
if [ "x$fpu" != "x" ]; then
echo "$CFLAGS" | grep -q -- '-mfpu=' || CFLAGS="$CFLAGS -mfpu=$fpu"
echo "$ASFLAGS" | grep -q -- '-mfpu=' || ASFLAGS="$ASFLAGS -mfpu=$fpu"
floatabi_set_by_gcc=`$CC -v 2>&1 | grep -q -- --with-float= && echo yes` || true
if [ "$floatabi_set_by_gcc" != "yes" ]; then
echo "$CFLAGS" | grep -q -- '-mfloat-abi=' || CFLAGS="$CFLAGS -mfloat-abi=softfp"
echo "$ASFLAGS" | grep -q -- '-mfloat-abi=' || ASFLAGS="$ASFLAGS -mfloat-abi=softfp"
fi
fi
# must disable thumb as recompiler can't handle it
if check_define __thumb__; then
CFLAGS="$CFLAGS -marm"
fi
# add -ldl for helix support
need_dl=yes
# warn about common mistakes
if [ "$platform" != "gp2x" -a "$have_armv5" != "yes" ]; then
if ! echo "$CFLAGS" | grep -q -- '-mcpu=\|-march='; then
@ -286,34 +224,26 @@ arm*)
esac
case "$platform" in
rpi1 | rpi2 | generic | opendingux)
generic)
need_sdl="yes"
;;
esac
# basic compiler test
cat > $TMPC <<EOF
int main (int argc, char *argv[]) { return 0; }
EOF
if ! compile_binary; then
fail "compiler test failed, please check config.log"
fi
# header/library presence tests
check_zlib()
{
cat > $TMPC <<EOF
#include <zlib.h>
int main (int argc, char *argv[]) { uncompress(0, 0, 0, 0); }
int main(void) { uncompress(0, 0, 0, 0); }
EOF
compile_binary "$@"
compile_binary
}
check_libpng()
{
cat > $TMPC <<EOF
#include <png.h>
int main (int argc, char *argv[]) { png_init_io(0, 0); }
void main() { png_init_io(0, 0); }
EOF
# compile_binary
compile_object
@ -324,7 +254,7 @@ check_oss()
cat > $TMPC <<EOF
#include <sys/soundcard.h>
#include <sys/ioctl.h>
int main (int argc, char *argv[]) { int a=0; ioctl(0, SNDCTL_DSP_SETFMT, &a); }
void main() { int a=0; ioctl(0, SNDCTL_DSP_SETFMT, &a); }
EOF
compile_binary
}
@ -333,7 +263,7 @@ check_alsa()
{
cat > $TMPC <<EOF
#include <alsa/asoundlib.h>
int main (int argc, char *argv[]) { snd_pcm_open(0, 0, 0, 0); }
void main() { snd_pcm_open(0, 0, 0, 0); }
EOF
compile_binary "$@"
}
@ -342,7 +272,7 @@ check_sdl()
{
cat > $TMPC <<EOF
#include <SDL.h>
int main (int argc, char *argv[]) { SDL_OpenAudio(0, 0); }
void main() { SDL_OpenAudio(0, 0); }
EOF
compile_binary "$@"
}
@ -351,49 +281,25 @@ check_libavcodec()
{
cat > $TMPC <<EOF
#include <libavcodec/avcodec.h>
int main (int argc, char *argv[]) { avcodec_decode_audio3(0, 0, 0, 0); }
void main() { avcodec_decode_audio3(0, 0, 0, 0); }
EOF
compile_object "$@"
}
check_libchdr()
{
cat > $TMPC <<EOF
#include <libchdr/chd.h>
int main (int argc, char *argv[]) { chd_open("", 0, NULL, NULL); }
EOF
compile_object "$@"
}
test -n "$SDL_CONFIG" || SDL_CONFIG="$(ls $SYSROOT/*bin*/sdl-config 2>/dev/null | grep /bin/sdl-config | head -n 1)"
test -n "$SDL_CONFIG" || SDL_CONFIG="$(ls $SYSROOT/*/*bin*/sdl-config 2>/dev/null | grep /bin/sdl-config | head -n 1)"
#test -n "$SDL_CONFIG" || SDL_CONFIG="$(ls $SYSROOT/*bin*/sdl2-config 2>/dev/null | grep /bin/sdl2-config | head -n 1)"
#test -n "$SDL_CONFIG" || SDL_CONFIG="$(ls $SYSROOT/*/*bin*/sdl2-config 2>/dev/null | grep /bin/sdl2-config | head -n 1)"
SDLVERSION=sdl && echo $SDL_CONFIG | grep -q sdl2 && SDLVERSION=sdl2
test -n "$SDL_CONFIG" || SDL_CONFIG=false
MAIN_LDLIBS="$LDLIBS -lm"
check_zlib -lz && MAIN_LDLIBS="$MAIN_LDLIBS -lz" || need_zlib="yes"
#MAIN_LDLIBS="$MAIN_LDLIBS -lz"
#check_zlib || fail "please install zlib (libz-dev)"
MAIN_LDLIBS="-lpng $MAIN_LDLIBS"
check_libpng || fail "please install libpng (libpng-dev)"
case "$have_libavcodec" in
y|Y|yes)
if check_libavcodec; then
have_libavcodec="yes"
need_dl=yes
else
have_libavcodec="no"
fi ;;
*) have_libavcodec="no" ;;
esac
#if check_libchdr; then
# have_libchdr="yes"
# MAIN_LDLIBS="-lchdr $MAIN_LDLIBS"
#fi
if check_libavcodec; then
have_libavcodec="yes"
# add -ldl if needed
case "$MAIN_LDLIBS" in
*"-ldl"*) ;;
*) MAIN_LDLIBS="-ldl $MAIN_LDLIBS" ;;
esac
fi
# find what audio support we can compile
if [ "x$sound_drivers" = "x" ]; then
@ -402,7 +308,7 @@ if [ "x$sound_drivers" = "x" ]; then
sound_drivers="$sound_drivers alsa"
MAIN_LDLIBS="-lasound $MAIN_LDLIBS"
fi
if [ "$need_sdl" = "yes" ] || check_sdl `$SDL_CONFIG --cflags --libs`; then
if [ "$need_sdl" = "yes" ] || check_sdl `sdl-config --cflags --libs`; then
sound_drivers="$sound_drivers sdl"
need_sdl="yes"
fi
@ -417,27 +323,17 @@ else
fi
if [ "$need_sdl" = "yes" ]; then
[ -x "$SDL_CONFIG" ] || \
which sdl-config > /dev/null || \
fail "sdl-config is missing; please install libsdl (libsdl1.2-dev)"
CFLAGS="$CFLAGS `$SDL_CONFIG --cflags`"
MAIN_LDLIBS="`$SDL_CONFIG --libs` $MAIN_LDLIBS"
SYSLIBS="$SYSLIBS -ldl"
need_dl=yes
check_sdl `$SDL_CONFIG --libs` || fail "please install libsdl (libsdl1.2-dev)"
if [ "$SDLVERSION" = "sdl2" ]; then
CFLAGS="$CFLAGS -D__USE_SDL2__"
fi
CFLAGS="$CFLAGS `sdl-config --cflags`"
MAIN_LDLIBS="`sdl-config --libs` $MAIN_LDLIBS"
check_sdl `sdl-config --libs` || fail "please install libsdl (libsdl1.2-dev)"
fi
# add -ldl if needed
if [ "$need_dl" = "yes" ]; then
case "$MAIN_LDLIBS" in
*"-ldl"*) ;;
*) MAIN_LDLIBS="$MAIN_LDLIBS -ldl" ;;
esac
fi
if check_option -Wno-unused_result; then
cat > $TMPC <<EOF
void test(void *f, void *d) { fread(d, 1, 1, f); }
EOF
if compile_object -Wno-unused-result; then
CFLAGS="$CFLAGS -Wno-unused-result"
fi
@ -445,17 +341,15 @@ fi
test "x$have_armv6" != "x" || have_armv6="no"
test "x$have_armv7" != "x" || have_armv7="no"
test "x$have_libavcodec" != "x" || have_libavcodec="no"
test "x$have_libchdr" != "x" || have_libchdr="no"
echo "architecture $ARCH"
echo "platform $platform"
echo "sound drivers $sound_drivers"
echo "C compiler $CC"
echo "C compiler flags $MFLAGS $CFLAGS"
echo "C compiler flags $CFLAGS"
echo "libraries $MAIN_LDLIBS"
echo "linker flags $LDFLAGS"
echo "libavcodec (mp3) $have_libavcodec"
#echo "libchdr $have_libchdr"
# echo "ARMv7 optimizations $have_armv7"
echo "# Automatically generated by configure" > $config_mak
@ -466,10 +360,8 @@ echo >> $config_mak
echo "CC = $CC" >> $config_mak
echo "CXX = $CXX" >> $config_mak
echo "AS = $AS" >> $config_mak
echo "STRIP = $STRIP" >> $config_mak
echo "LD = $LD" >> $config_mak
echo "CFLAGS += $MFLAGS $CFLAGS" >> $config_mak
echo "ASFLAGS += $MFLAGS $ASFLAGS" >> $config_mak
echo "CFLAGS += $CFLAGS" >> $config_mak
echo "ASFLAGS += $ASFLAGS" >> $config_mak
echo "LDFLAGS += $LDFLAGS" >> $config_mak
echo "LDLIBS += $MAIN_LDLIBS" >> $config_mak
echo >> $config_mak
@ -477,31 +369,18 @@ echo >> $config_mak
echo "ARCH = $ARCH" >> $config_mak
echo "PLATFORM = $platform" >> $config_mak
echo "SOUND_DRIVERS = $sound_drivers" >> $config_mak
if [ "$have_gles" = "yes" ]; then
echo "HAVE_GLES = 1" >> $config_mak
fi
if [ "$have_libavcodec" = "yes" ]; then
echo "HAVE_LIBAVCODEC = 1" >> $config_mak
fi
if [ "$have_libchdr" = "yes" ]; then
echo "HAVE_LIBCHDR = 1" >> $config_mak
fi
if [ "$need_zlib" = "yes" ]; then
echo "PLATFORM_ZLIB = 1" >> $config_mak
fi
if [ "$ARCH" = "arm" -a "$have_armv6" != "yes" -a "$have_armv7" != "yes" ]; then
# pass info to cyclone not to use newer arm arch instructions
echo "HAVE_ARMv6 = 0" >> $config_mak
fi
# GP2X toolchains are too old for UAL asm,
# so add this here to not litter main Makefile
#if [ "$platform" = "gp2x" ]; then
# echo >> $config_mak
# echo '%.o: %.S' >> $config_mak
# echo ' $(CC) $(CFLAGS) -E -c $^ -o /tmp/$(notdir $@).s' >> $config_mak
# echo ' $(AS) $(ASFLAGS) /tmp/$(notdir $@).s -o $@' >> $config_mak
#fi
if [ "$platform" = "g1p2x" ]; then
echo >> $config_mak
echo "%.o: %.S" >> $config_mak
echo " $(CC) $(CFLAGS) -E -c $^ -o /tmp/$(notdir $@).s" >> $config_mak
echo " $(AS) $(ASFLAGS) /tmp/$(notdir $@).s -o $@" >> $config_mak
fi
# use pandora's skin (for now)
test -e skin || ln -s platform/pandora/skin skin

File diff suppressed because it is too large Load diff

8092
cpu/DrZ80/drz80.s Normal file

File diff suppressed because it is too large Load diff

@ -1 +1 @@
Subproject commit 3ac7cf1bdeecb60e2414980e8dc72ff092f69769
Subproject commit 7ddcd35c8b2a8248257bd89ef989095639c29c08

View file

@ -8,12 +8,9 @@
**/
#ifndef HAVE_ARMv6
#define HAVE_ARMv6 1
#endif
#define USE_MS_SYNTAX 0
#define CYCLONE_FOR_GENESIS 2
#define COMPRESS_JUMPTABLE 0
#define COMPRESS_JUMPTABLE 1
#define MEMHANDLERS_ADDR_MASK 0
#define MEMHANDLERS_NEED_PC 0

View file

@ -1,2 +0,0 @@
#define HAVE_ARMv6 0
#include "cyclone_config.h"

View file

@ -14,7 +14,6 @@
#include "cz80.h"
#if PICODRIVE_HACKS
#include <pico/pico_int.h>
#include <pico/memory.h>
#endif
@ -107,7 +106,7 @@ void Cz80_Init(cz80_struc *CPU)
for (i = 0; i < CZ80_FETCH_BANK; i++)
{
CPU->Fetch[i] = (FPTR)cz80_bad_address - (i << CZ80_FETCH_SFT);
CPU->Fetch[i] = (FPTR)cz80_bad_address;
#if CZ80_ENCRYPTED_ROM
CPU->OPFetch[i] = 0;
#endif
@ -196,9 +195,10 @@ void Cz80_Init(cz80_struc *CPU)
CPU->pzR16[0] = pzBC;
CPU->pzR16[1] = pzDE;
CPU->pzR16[2] = pzHL;
CPU->pzR16[3] = pzFA;
CPU->pzR16[3] = pzAF;
zIX = zIY = 0xffff;
zF = ZF;
CPU->Interrupt_Callback = Cz80_Interrupt_Callback;
}
@ -210,8 +210,7 @@ void Cz80_Init(cz80_struc *CPU)
void Cz80_Reset(cz80_struc *CPU)
{
// I, R, CPU and interrupts logic is reset, registers are untouched
memset(&CPU->R, 0, (FPTR)&CPU->BasePC - (FPTR)&CPU->R);
memset(CPU, 0, (FPTR)&CPU->BasePC - (FPTR)CPU);
Cz80_Set_Reg(CPU, CZ80_PC, 0);
}
@ -244,6 +243,7 @@ INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles)
UINT32 adr = 0;
UINT32 res;
UINT32 val;
int afterEI = 0;
union16 *data;
PC = CPU->PC;
@ -253,46 +253,41 @@ INT32 Cz80_Exec(cz80_struc *CPU, INT32 cycles)
CPU->ICount = cycles - CPU->ExtraCycles;
CPU->ExtraCycles = 0;
if (!CPU->HaltState)
{
Cz80_Exec:
if (CPU->Status)
{
if (CPU->Status & CZ80_HAS_NMI)
if (CPU->ICount > 0)
{
zIFF1 = 0;
CPU->Status &= ~(CZ80_HALTED | CZ80_HAS_NMI);
CPU->ExtraCycles += 11;
PUSH_16(zRealPC);
SET_PC(0x66);
} else if (CPU->Status & CZ80_HAS_INT)
{
CHECK_INT
} else if (CPU->Status & CZ80_HALTED)
{
goto Cz80_Exec_End;
}
CPU->ICount -= CPU->ExtraCycles;
CPU->ExtraCycles = 0;
}
if (CPU->ICount > 0)
{
Cz80_Exec_nocheck:
data = pzHL;
Opcode = READ_OP();
data = pzHL;
Opcode = READ_OP();
#if CZ80_EMULATE_R_EXACTLY
zR++;
zR++;
#endif
#include "cz80_op.c"
#include "cz80_op.c"
}
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
if (!((CPU->Status & CZ80_HALTED) && CPU->ICount > 0))
cycles -= CPU->ICount;
CPU->ICount = 0;
cycles -= CPU->ICount;
#if !CZ80_EMULATE_R_EXACTLY
zR = (zR + (cycles >> 2)) & 0x7f;
#endif
@ -309,21 +304,29 @@ void Cz80_Set_IRQ(cz80_struc *CPU, INT32 line, INT32 state)
{
if (line == IRQ_LINE_NMI)
{
if (state)
CPU->Status |= CZ80_HAS_NMI;
else
CPU->Status &= ~CZ80_HAS_NMI;
} else
zIFF1 = 0;
CPU->ExtraCycles += 11;
CPU->HaltState = 0;
PUSH_16(CPU->PC - CPU->BasePC)
Cz80_Set_Reg(CPU, CZ80_PC, 0x66);
}
else
{
CPU->IRQLine = line;
CPU->IRQState = state;
if (state)
if (state != CLEAR_LINE)
{
if (zIFF1)
CPU->Status |= CZ80_HAS_INT;
} else
{
CPU->Status &= ~CZ80_HAS_INT;
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
}
}
}
@ -339,13 +342,13 @@ UINT32 Cz80_Get_Reg(cz80_struc *CPU, INT32 regnum)
{
case CZ80_PC: return (CPU->PC - CPU->BasePC);
case CZ80_SP: return zSP;
case CZ80_FA: return zFA;
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_FA2: return zFA2;
case CZ80_AF2: return zAF2;
case CZ80_BC2: return zBC2;
case CZ80_DE2: return zDE2;
case CZ80_HL2: return zHL2;
@ -354,7 +357,7 @@ UINT32 Cz80_Get_Reg(cz80_struc *CPU, INT32 regnum)
case CZ80_IM: return zIM;
case CZ80_IFF1: return zIFF1;
case CZ80_IFF2: return zIFF2;
case CZ80_HALT: return CPU->Status & CZ80_HALTED;
case CZ80_HALT: return CPU->HaltState;
case CZ80_IRQ: return CPU->IRQState;
default: return 0;
}
@ -378,13 +381,13 @@ void Cz80_Set_Reg(cz80_struc *CPU, INT32 regnum, UINT32 val)
break;
case CZ80_SP: zSP = val; break;
case CZ80_FA: zFA = 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_FA2: zFA2 = 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;
@ -393,7 +396,7 @@ void Cz80_Set_Reg(cz80_struc *CPU, INT32 regnum, UINT32 val)
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->Status = !!val * CZ80_HALTED; break;
case CZ80_HALT: CPU->HaltState = val; break;
case CZ80_IRQ: CPU->IRQState = val; break;
default: break;
}

View file

@ -11,80 +11,71 @@
#ifndef CZ80_H
#define CZ80_H
// uintptr_t
#include <stdlib.h>
#ifndef _MSC_VER
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <pico/pico_port.h>
/******************************/
/* Compiler dependant defines */
/******************************/
#ifndef UINT8
#define UINT8 u8
#define UINT8 unsigned char
#endif
#ifndef INT8
#define INT8 s8
#define INT8 signed char
#endif
#ifndef UINT16
#define UINT16 u16
#define UINT16 unsigned short
#endif
#ifndef INT16
#define INT16 s16
#define INT16 signed short
#endif
#ifndef UINT32
#define UINT32 u32
#define UINT32 unsigned int
#endif
#ifndef INT32
#define INT32 s32
#define INT32 signed int
#endif
#ifndef FPTR
#define FPTR uptr
#define FPTR unsigned long
#endif
/*************************************/
/* Z80 core Structures & definitions */
/*************************************/
// NB this must have at least the value of (16-Z80_MEM_SHIFT)
#define CZ80_FETCH_BITS 6 // [4-12] default = 8
#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 CPU_IS_LE
#define PICODRIVE_HACKS 1
#define CZ80_LITTLE_ENDIAN 1
#define CZ80_USE_JUMPTABLE 1
#define CZ80_BIG_FLAGS_ARRAY 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 CZ80_EMULATE_R_EXACTLY 1
#define zR8(A) (*CPU->pzR8[A])
#define zR16(A) (CPU->pzR16[A]->W)
#define pzFA &(CPU->FA)
#define zFA CPU->FA.W
#define zlFA CPU->FA.B.L
#define zhFA CPU->FA.B.H
#define zA zlFA
#define zF zhFA
#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
@ -107,11 +98,11 @@ extern "C" {
#define zH zhHL
#define zL zlHL
#define zFA2 CPU->FA2.W
#define zlFA2 CPU->FA2.B.L
#define zhFA2 CPU->FA2.B.H
#define zA2 zhFA2
#define zF2 zlFA2
#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
@ -170,10 +161,6 @@ extern "C" {
#define CZ80_IFF_SFT CZ80_PF_SFT
#define CZ80_IFF CZ80_PF
#define CZ80_HAS_INT 0x1
#define CZ80_HAS_NMI 0x2
#define CZ80_HALTED 0x4
#ifndef IRQ_LINE_STATE
#define IRQ_LINE_STATE
#define CLEAR_LINE 0 /* clear (a fired, held or pulsed) line */
@ -187,13 +174,13 @@ enum
{
CZ80_PC = 1,
CZ80_SP,
CZ80_FA,
CZ80_AF,
CZ80_BC,
CZ80_DE,
CZ80_HL,
CZ80_IX,
CZ80_IY,
CZ80_FA2,
CZ80_AF2,
CZ80_BC2,
CZ80_DE2,
CZ80_HL2,
@ -232,7 +219,7 @@ typedef struct cz80_t
union16 BC;
union16 DE;
union16 HL;
union16 FA;
union16 AF;
};
};
@ -244,14 +231,14 @@ typedef struct cz80_t
union16 BC2;
union16 DE2;
union16 HL2;
union16 FA2;
union16 AF2;
union16 R;
union16 IFF;
UINT8 I;
UINT8 IM;
UINT8 Status;
UINT8 HaltState;
UINT8 dummy;
INT32 IRQLine;

View file

@ -200,15 +200,9 @@ OP_LD_mNN_xx:
POP
-----------------------------------------*/
OP(0xf1): // POP AF
OP_POP_AF:
POP_16(res)
zA = res >> 8;
zF = res & 0xFF;
RET(10)
OP(0xc1): // POP BC
OP(0xd1): // POP DE
OP(0xf1): // POP AF
OP_POP_RR:
data = CPU->pzR16[(Opcode >> 4) & 3];
@ -221,14 +215,9 @@ OP_POP:
PUSH
-----------------------------------------*/
OP(0xf5): // PUSH AF
OP_PUSH_AF:
PUSH_16((zA << 8) | zF);
RET(11)
OP(0xc5): // PUSH BC
OP(0xd5): // PUSH DE
OP(0xf5): // PUSH AF
OP_PUSH_RR:
data = CPU->pzR16[(Opcode >> 4) & 3];
@ -243,9 +232,9 @@ OP_PUSH:
OP(0x08): // EX AF,AF'
OP_EX_AF_AF2:
res = zFA;
zFA = zFA2;
zFA2 = res;
res = zAF;
zAF = zAF2;
zAF2 = res;
RET(4)
OP(0xeb): // EX DE,HL
@ -697,28 +686,37 @@ OP_CCF:
OP(0x76): // HALT
OP_HALT:
CPU->Status |= CZ80_HALTED;
RET(4)
CPU->HaltState = 1;
CPU->ICount = 0;
goto Cz80_Check_Interrupt;
OP(0xf3): // DI
OP_DI:
zIFF = 0;
USE_CYCLES(4)
goto Cz80_Exec_nocheck;
RET(4)
OP(0xfb): // EI
OP_EI:
USE_CYCLES(4)
if (!zIFF1)
{
zIFF1 = zIFF2 = (1 << 2);
while (GET_OP() == 0xfb)
{
USE_CYCLES(4)
PC++;
#if CZ80_EMULATE_R_EXACTLY
zR++;
#endif
}
if (CPU->IRQState)
{
CPU->Status |= CZ80_HAS_INT;
CPU->ExtraCycles -= CPU->ICount;
CPU->ICount = 0;
afterEI = 1;
CPU->ExtraCycles += 1 - CPU->ICount;
CPU->ICount = 1;
}
}
zIFF1 = zIFF2 = (1 << 2);
else zIFF2 = (1 << 2);
goto Cz80_Exec_nocheck;
/*-----------------------------------------

View file

@ -283,7 +283,6 @@ switch (Opcode)
OPCB(0x7d): // BIT 7,L
OPCB(0x7f): // BIT 7,A
zF = (zF & CF) | HF | SZ_BIT[zR8(Opcode & 7) & (1 << ((Opcode >> 3) & 7))];
zF = (zF & ~(XF | YF)) | (zR8(Opcode & 7) & (XF | YF));
RET(8)
OPCB(0x46): // BIT 0,(HL)
@ -296,7 +295,6 @@ switch (Opcode)
OPCB(0x7e): // BIT 7,(HL)
src = READ_MEM8(zHL);
zF = (zF & CF) | HF | SZ_BIT[src & (1 << ((Opcode >> 3) & 7))];
zF = (zF & ~(XF | YF)) | (0xc0 & (XF | YF)); // TODO ZEXALL hack, need WZ...
RET(12)
/*-----------------------------------------

View file

@ -407,14 +407,30 @@ OP_SBC16:
RET(8)
/*-----------------------------------------
RETI/RETN
RETN
-----------------------------------------*/
// works the same, but Z80 PIO can detect the opcode
OPED(0x45): // RETN
OPED(0x55): // RETN
OPED(0x65): // RETN
OPED(0x75): // 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
@ -422,14 +438,6 @@ OP_SBC16:
OPED(0x7d): // RETI
POP_16(res);
SET_PC(res);
if (!zIFF1 && zIFF2)
{
if (CPU->IRQState)
{
CPU->Status |= CZ80_HAS_INT;
}
}
zIFF1 = zIFF2;
RET(10)
/*-----------------------------------------
@ -489,8 +497,8 @@ OP_LDX:
val = READ_MEM8(zHL++);
WRITE_MEM8(zDE++, val);
zBC--;
USE_CYCLES(21)
} while (zBC && (CPU->ICount > -4) && !CPU->Status);
USE_CYCLES(17)
} while (zBC && (CPU->ICount > 0));
goto OP_LDXR;
OPED(0xb8): // LDDR
@ -499,8 +507,8 @@ OP_LDX:
val = READ_MEM8(zHL--);
WRITE_MEM8(zDE--, val);
zBC--;
USE_CYCLES(21)
} while (zBC && (CPU->ICount > -4) && !CPU->Status);
USE_CYCLES(17)
} while (zBC && (CPU->ICount > 0));
OP_LDXR:
F = zF & (SF | ZF | CF);
@ -513,11 +521,10 @@ OP_LDXR:
#if CZ80_EMULATE_R_EXACTLY
zR--;
#endif
ADD_CYCLES(4)
goto Cz80_Exec;
goto Cz80_Exec_End;
}
zF = F;
ADD_CYCLES(4+5)
ADD_CYCLES(5)
goto Cz80_Exec;
/*-----------------------------------------
@ -557,8 +564,8 @@ OP_CPX:
if (res & 0x08) F |= XF;
if (zBC) F |= VF;
zF = F;
USE_CYCLES(21)
} while (zBC && !(F & ZF) && (CPU->ICount > -4) && !CPU->Status);
USE_CYCLES(17)
} while (zBC && !(F & ZF) && (CPU->ICount > 0));
goto OP_CPXR;
OPED(0xb9): // CPDR
@ -573,8 +580,8 @@ OP_CPX:
if (res & 0x08) F |= XF;
if (zBC) F |= VF;
zF = F;
USE_CYCLES(21)
} while (zBC && !(F & ZF) && (CPU->ICount > -4) && !CPU->Status);
USE_CYCLES(17)
} while (zBC && !(F & ZF) && (CPU->ICount > 0));
OP_CPXR:
if (zBC && !(F & ZF))
@ -583,10 +590,9 @@ OP_CPXR:
#if CZ80_EMULATE_R_EXACTLY
zR--;
#endif
ADD_CYCLES(4)
goto Cz80_Exec;
goto Cz80_Exec_End;
}
ADD_CYCLES(4+5)
ADD_CYCLES(5)
goto Cz80_Exec;
/*-----------------------------------------
@ -608,7 +614,7 @@ OP_INX:
F = SZ[zB];
res = ((UINT32)(zC - 1) & 0xff) + (UINT32)val;
if (val & SF) F |= NF;
if (res < val) F |= HF | CF;
if (res & 0x100) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;
zF = F;
RET(12)
@ -623,8 +629,8 @@ OP_INX:
val = IN(zBC);
zB--;
WRITE_MEM8(zHL++, val);
USE_CYCLES(21)
} while (zB && (CPU->ICount > -4) && !CPU->Status);
USE_CYCLES(17)
} while (zB && (CPU->ICount > 0));
goto OP_INXR;
OPED(0xba): // INDR
@ -633,14 +639,14 @@ OP_INX:
val = IN(zBC);
zB--;
WRITE_MEM8(zHL--, val);
USE_CYCLES(21)
} while (zB && (CPU->ICount > -4) && !CPU->Status);
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 < val) F |= HF | CF;
if (res & 0x100) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;
zF = F;
if (zB)
@ -649,10 +655,9 @@ OP_INXR:
#if CZ80_EMULATE_R_EXACTLY
zR--;
#endif
ADD_CYCLES(4)
goto Cz80_Exec;
goto Cz80_Exec_End;
}
ADD_CYCLES(4+5);
ADD_CYCLES(5);
goto Cz80_Exec;
/*-----------------------------------------
@ -674,8 +679,8 @@ OP_OUTX:
F = SZ[zB];
res = (UINT32)zL + (UINT32)val;
if (val & SF) F |= NF;
if (res < val) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;
if (res & 0x100) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) - zB] & PF;
zF = F;
RET(12)
@ -689,8 +694,8 @@ OP_OUTX:
val = READ_MEM8(zHL++);
zB--;
OUT(zBC, val);
USE_CYCLES(21)
} while (zB && (CPU->ICount > -4) && !CPU->Status);
USE_CYCLES(17)
} while (zB && (CPU->ICount > 0));
goto OP_OTXR;
OPED(0xbb): // OTDR
@ -699,15 +704,15 @@ OP_OUTX:
val = READ_MEM8(zHL--);
zB--;
OUT(zBC, val);
USE_CYCLES(21)
} while (zB && (CPU->ICount > -4) && !CPU->Status);
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 < val) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) ^ zB] & PF;
if (res & 0x100) F |= HF | CF;
F |= SZP[(UINT8)(res & 0x07) - zB] & PF;
zF = F;
if (zB)
{
@ -715,10 +720,9 @@ OP_OTXR:
#if CZ80_EMULATE_R_EXACTLY
zR--;
#endif
ADD_CYCLES(4)
goto Cz80_Exec;
goto Cz80_Exec_End;
}
ADD_CYCLES(4+5)
ADD_CYCLES(5)
goto Cz80_Exec;
}

View file

@ -70,7 +70,7 @@ switch (Opcode)
OPXY(0x5c): // LD E,HX
OPXY(0x7c): // LD A,HX
zR8((Opcode >> 3) & 7) = data->B.H;
RET(4)
RET(5)
OPXY(0x45): // LD B,LX
OPXY(0x4d): // LD C,LX
@ -78,7 +78,7 @@ switch (Opcode)
OPXY(0x5d): // LD E,LX
OPXY(0x7d): // LD A,LX
zR8((Opcode >> 3) & 7) = data->B.L;
RET(4)
RET(5)
OPXY(0x60): // LD HX,B
OPXY(0x61): // LD HX,C
@ -86,7 +86,7 @@ switch (Opcode)
OPXY(0x63): // LD HX,E
OPXY(0x67): // LD HX,A
data->B.H = zR8(Opcode & 7);
RET(4)
RET(5)
OPXY(0x68): // LD LX,B
OPXY(0x69): // LD LX,C
@ -94,15 +94,15 @@ switch (Opcode)
OPXY(0x6b): // LD LX,E
OPXY(0x6f): // LD LX,A
data->B.L = zR8(Opcode & 7);
RET(4)
RET(5)
OPXY(0x65): // LD HX,LX
data->B.H = data->B.L;
RET(4)
RET(5)
OPXY(0x6c): // LD LX,HX
data->B.L = data->B.H;
RET(4)
RET(5)
OPXY(0x06): // LD B,#imm
OPXY(0x0e): // LD C,#imm
@ -113,11 +113,11 @@ switch (Opcode)
OPXY(0x26): // LD HX,#imm
data->B.H = READ_ARG();
RET(4)
RET(5)
OPXY(0x2e): // LD LX,#imm
data->B.L = READ_ARG();
RET(4)
RET(5)
OPXY(0x0a): // LD A,(BC)
goto OP_LOAD_A_mBC;
@ -194,9 +194,8 @@ switch (Opcode)
OPXY(0xc1): // POP BC
OPXY(0xd1): // POP DE
goto OP_POP_RR;
OPXY(0xf1): // POP AF
goto OP_POP_AF;
goto OP_POP_RR;
OPXY(0xe1): // POP IX
goto OP_POP;
@ -207,9 +206,8 @@ switch (Opcode)
OPXY(0xc5): // PUSH BC
OPXY(0xd5): // PUSH DE
goto OP_PUSH_RR;
OPXY(0xf5): // PUSH AF
goto OP_PUSH_AF;
goto OP_PUSH_RR;
OPXY(0xe5): // PUSH IX
goto OP_PUSH;
@ -244,12 +242,12 @@ switch (Opcode)
OPXY(0x24): // INC HX
data->B.H++;
zF = (zF & CF) | SZHV_inc[data->B.H];
RET(4)
RET(5)
OPXY(0x2c): // INC LX
data->B.L++;
zF = (zF & CF) | SZHV_inc[data->B.L];
RET(4)
RET(5)
OPXY(0x34): // INC (IX+o)
adr = data->W + (INT8)READ_ARG();
@ -270,12 +268,12 @@ switch (Opcode)
OPXY(0x25): // DEC HX
data->B.H--;
zF = (zF & CF) | SZHV_dec[data->B.H];
RET(4)
RET(5)
OPXY(0x2d): // DEC LX
data->B.L--;
zF = (zF & CF) | SZHV_dec[data->B.L];
RET(4)
RET(5)
OPXY(0x35): // DEC (IX+o)
adr = data->W + (INT8)READ_ARG();
@ -298,10 +296,12 @@ switch (Opcode)
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)
@ -326,10 +326,12 @@ switch (Opcode)
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)
@ -354,10 +356,12 @@ switch (Opcode)
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)
@ -382,10 +386,12 @@ switch (Opcode)
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)
@ -410,10 +416,12 @@ switch (Opcode)
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)
@ -438,10 +446,12 @@ switch (Opcode)
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)
@ -466,10 +476,12 @@ switch (Opcode)
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)
@ -494,10 +506,12 @@ switch (Opcode)
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)

View file

@ -48,7 +48,11 @@
#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)]
@ -59,13 +63,17 @@
#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; \
uptr v = z80_write_map[a >> Z80_MEM_SHIFT]; \
unsigned long v = z80_write_map[a >> Z80_MEM_SHIFT]; \
if (map_flag_set(v)) \
((z80_write_f *)(v << 1))(a, d); \
else \
@ -74,7 +82,11 @@
#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; }
@ -82,36 +94,36 @@
#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->Status &= ~(CZ80_HALTED|CZ80_HAS_INT); \
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) \
#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

@ -1,246 +0,0 @@
************************************************
* *
* CZ80 (Z80 CPU emulator) version 0.91 *
* Compiled with Dev-C++ *
* Copyright 2004-2005 Stéphane Dallongeville *
* *
************************************************
CZ80 is a Z80 CPU emulator, priorities were given to :
- code size
- speed
- accuracy
- portablity
It supports almost all undocumented opcodes and flags.
The emulator can be freely distribued and used for any non commercial
project as long you don't forget to credit me somewhere :)
If you want some support about the CZ80, you can contact me on
the Gens forum (http://gens.consolemul.com then go to the forum).
You should find the following files in the emulation pack :
- cz80.h -> header file (prototypes, declarations...)
- cz80.c -> contains emulation core itself
- cz80.inc -> contains most used macros
- cz80jmp.inc -> Jump table definition when Jump Table used
- cz80exec.inc -> contains the major Cz80_Exec(...) function
- cz80_op.inc -> contains code for simple Z80 opcodes emulation
- cz80_opCB.inc -> contains code for CB prefixed Z80 opcodes emulation
- cz80_opED.inc -> contains code for ED prefixed Z80 opcodes emulation
- cz80_opXY.inc -> contains code for DD/FD prefixed Z80 opcodes emulation
- cz80_opXYCB.inc -> contains code for DD/FD + CB prefixed Z80 opcodes emulation
- readme.txt -> the current file you're reading ;)
* How compile the emulator ?
****************************
The emulator has been written with Dev-CPP 4.9.X.X
You will maybe need to modify the u8, u16, u32, s8, s16, s32 and FASTCALL
definitions (cz80.h) according to your C compiler and the target system.
Then compile the cz80.c file, you should obtain a cz80.o (or cz80.obj) file...
at this moment, you're ready to use the emulator just by linking the file in your project :)
* How to use the emulator ?
***************************
1) Include the header file in your source :
------------------------------------------
#include "cz80.h"
2) Init the CZ80 core :
-----------------------
If you want to use the internal CZ80 context offered :
Cz80_Init(&CZ80);
but you can also define your own CZ80 context :
cz80_struc My_Z80;
....
Cz80_Init(&My_Z80);
You'll can emulate as many Z80 CPU as you want by defining severals CZ80 contexts.
3) Set up your fetch region (where the Z80 will run code from) :
----------------------------------------------------------------
Cz80_Set_Fetch(&CZ80, 0x0000, 0x7FFF, (u32) your_ROM);
Cz80_Set_Fetch(&CZ80, 0xA000, 0xFFFF, (u32) your_RAM);
...
4) Set up your memory (where the Z80 will read and write data) :
----------------------------------------------------------------
Cz80_Set_ReadB(&CZ80, your_z80readbyte_function);
Cz80_Set_WriteB(&CZ80, your_z80readbyte_function);
You can improve CZ80 performance by using WORD read/write function.
For that, you need to enable the 'CZ80_USE_WORD_HANDLER' define in cz80.h file.
In this case, you'll need to add that :
#if CZ80_USE_WORD_HANDLER
Cz80_Set_ReadW(&CZ80, your_z80readword_function);
Cz80_Set_WriteW(&CZ80, your_z80readword_function);
#endif
Your read function need to be of CZ80_READ type :
typedef u32 FASTCALL CZ80_READ(u32 adr);
Your write function need to be of CZ80_WRITE type :
typedef void FASTCALL CZ80_WRITE(u32 adr, u32 data);
5) Set Up your port (where the Z80 will read and write IO data) :
-----------------------------------------------------------------
Cz80_Set_INPort(&CZ80, your_z80readport_function);
Cz80_Set_OUTPort(&CZ80, your_z80writport_function);
Your readPort function need to be of CZ80_READ type :
typedef u32 FASTCALL CZ80_READ(u32 adr);
Your writePort function need to be of CZ80_WRITE type :
typedef void FASTCALL CZ80_WRITE(u32 adr, u32 data);
6) Set Up your interrupt callback function :
--------------------------------------------
Cz80_Set_IRQ_Callback(&CZ80, your_z80irqcallback_function);
Your IRQ callback function need to be of CZ80_INT_CALLBACK type :
typedef s32 FASTCALL CZ80_INT_CALLBACK(s32 param);
If you don't understand what i am talking about here, just ignore...
it's not needed in almost case.
6) Set Up your RETI callback function :
---------------------------------------
Cz80_Set_RETI_Callback(&CZ80, your_z80reticallback_function);
Your RETI callback function need to be of CZ80_RETI_CALLBACKtype :
typedef void FASTCALL CZ80_RETI_CALLBACK();
Again, if you don't understand what i am talking about here, ignore...
7) Reset the CZ80 core before fisrt use :
-----------------------------------------
Cz80_Reset(&CZ80);
8) Do some cycles :
-------------------
Then it's time to really do some work, if you want to execute 1000 cycles, just do :
cycles_done = Cz80_Exec(&CZ80, 1000);
Cz80_Exec function return the number of cycles actually done.
Since each instruction take more than 1 cycle, Cz80_Exec will execute a bit more than
you requested, for instance here, it can return 1008 cycles instead of 1000.
In this case, adjust the number of cycle to do like that :
cycles_by_frame = 4800;
extra_cycles = 0;
while (true)
{
...
extra_cycles = CZ80_Exec(&CZ80, cycles_by_frame - extra_cycles) - cycles_by_frame;
...
}
If Cz80_Exec returns a negatif value, an error occured.
9) Do an interrupt request :
----------------------------
Cz80_Set_IRQ(&CZ80, 0);
or for a NMI :
Cz80_Set_NMI(&CZ80);
10) Cancel an interrupt request :
---------------------------------
Cz80_Clear_IRQ(&CZ80);
or for a NMI :
Cz80_Clear_NMI(&CZ80);
* Switchs
*********
There are severals switchs in the cz80.h file which permit you to configure
CZ80 depending your needs.
- CZ80_FETCH_BITS (default = 4)
This defines the number of bits to select fetch region.
This value must be 4 <= X <= 12
Greater value offers permit to have more fetch region.
In almost case, 4 is enough, but if you have fetch region smaller than 0x1000 bytes,
increase this value.
- CZ80_LITTLE_ENDIAN
Define the endianess of the target platform.
x86 CPU use Little Endian.
- CZ80_USE_JUMPTABLE
Set it to 1 to use Jump table instead of big case statement.
This can bring some small speed improvemen.
Be careful, some compiler doesn't support (computed label) so it's
saffer to not use it.
- CZ80_SIZE_OPT
Add some extras optimisation for the code size versus speed.
Minor changes anyway...
- CZ80_USE_WORD_HANDLER
See the "Set Up Memory" section for more détail.
- CZ80_EXACT
Enable accurate emulation of extended undocumented opcode and flags.
minor speed decrease when activated.
Even without that flag, CZ80 is already uite accurate, keep it
disable unless you need it or if speed isn't important for you.
- CZ80_DEBUG
Used by me, keep it disable :p
* History
*********
Version 0.90 :
--------------
* Initial release for debugging purpose ^^

View file

@ -8,7 +8,7 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <pico/pico_int.h>
#include "../pico/pico_int.h"
#include "debug.h"
static char pdb_pending_cmds[128];

View file

@ -26,6 +26,6 @@ int pdb_net_connect(const char *host, const char *port);
#else
static __inline int pdb_net_connect(const char *host, const char *port) {return 0;}
static inline int pdb_net_connect(const char *host, const char *port) {return 0;}
#endif

View file

@ -10,29 +10,17 @@
#include <pico/pico_int.h>
#include "cmn.h"
#if defined(__linux__) && (defined(__aarch64__) || defined(__VFP_FP__))
// might be running on a 64k-page kernel
#define PICO_PAGE_ALIGN 65536
#else
#define PICO_PAGE_ALIGN 4096
#endif
u8 ALIGNED(PICO_PAGE_ALIGN) tcache_default[DRC_TCACHE_SIZE];
u8 *tcache;
u8 __attribute__((aligned(4096))) tcache[DRC_TCACHE_SIZE];
void drc_cmn_init(void)
{
int ret;
tcache = plat_mem_get_for_drc(DRC_TCACHE_SIZE);
if (tcache == NULL)
tcache = tcache_default;
ret = plat_mem_set_exec(tcache, DRC_TCACHE_SIZE);
int ret = plat_mem_set_exec(tcache, sizeof(tcache));
elprintf(EL_STATUS, "drc_cmn_init: %p, %zd bytes: %d",
tcache, DRC_TCACHE_SIZE, ret);
tcache, sizeof(tcache), ret);
#ifdef __arm__
if (PicoIn.opt & POPT_EN_DRC)
if (PicoOpt & POPT_EN_DRC)
{
static int test_done;
if (!test_done)

View file

@ -1,44 +1,12 @@
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef unsigned int u32;
#define DRC_TCACHE_SIZE (4*1024*1024)
#define DRC_TCACHE_SIZE (2*1024*1024)
extern u8 *tcache;
extern u8 tcache[DRC_TCACHE_SIZE];
void drc_cmn_init(void);
void drc_cmn_cleanup(void);
#define BITMASK1(v0) (1 << (v0))
#define BITMASK2(v0,v1) ((1 << (v0)) | (1 << (v1)))
#define BITMASK3(v0,v1,v2) (BITMASK2(v0,v1) | (1 << (v2)))
#define BITMASK4(v0,v1,v2,v3) (BITMASK3(v0,v1,v2) | (1 << (v3)))
#define BITMASK5(v0,v1,v2,v3,v4) (BITMASK4(v0,v1,v2,v3) | (1 << (v4)))
#define BITMASK6(v0,v1,v2,v3,v4,v5) (BITMASK5(v0,v1,v2,v3,v4) | (1 << (v5)))
#define BITRANGE(v0,v1) (BITMASK1(v1+1)-BITMASK1(v0)) // set with v0..v1
// binary search approach, since we don't have CLZ on ARM920T
#define FOR_ALL_BITS_SET_DO(mask, bit, code) { \
u32 __mask = mask; \
for (bit = 0; bit < 32 && mask; bit++, __mask >>= 1) { \
if (!(__mask & 0xffff)) \
bit += 16,__mask >>= 16; \
if (!(__mask & 0xff)) \
bit += 8, __mask >>= 8; \
if (!(__mask & 0xf)) \
bit += 4, __mask >>= 4; \
if (!(__mask & 0x3)) \
bit += 2, __mask >>= 2; \
if (!(__mask & 0x1)) \
bit += 1, __mask >>= 1; \
if (__mask & 0x1) { \
code; \
} \
} \
}
// inspired by https://graphics.stanford.edu/~seander/bithacks.html
static inline int count_bits(unsigned val)
{
val = val - ((val >> 1) & 0x55555555);
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}

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

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

@ -9,12 +9,6 @@
#ifndef __FAME_H__
#define __FAME_H__
// uintptr_t
#include <stdlib.h>
#ifndef _MSC_VER
#include <stdint.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -98,25 +92,14 @@ extern "C" {
/* Data definition */
/*******************/
#include <pico/pico_port.h>
/*
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
*/
typedef union
{
u8 B[4];
s8 SB[4];
u16 W[2];
s16 SW[2];
u32 D;
s32 SD;
unsigned char B;
signed char SB;
unsigned short W;
signed short SW;
unsigned int D;
signed int SD;
} famec_union32;
/* M68K CPU CONTEXT */
@ -142,9 +125,8 @@ typedef struct
unsigned int Opcode;
signed int cycles_needed;
unsigned short *PC;
uintptr_t BasePC;
unsigned long BasePC;
unsigned int flag_C;
unsigned int flag_V;
unsigned int flag_NotZ;
@ -154,19 +136,10 @@ typedef struct
unsigned int flag_S;
unsigned int flag_I;
unsigned char not_polling;
unsigned char pad[3];
uintptr_t Fetch[M68K_FETCHBANK1];
unsigned long Fetch[M68K_FETCHBANK1];
} M68K_CONTEXT;
typedef enum
{
fm68k_reason_emulate = 0,
fm68k_reason_init,
fm68k_reason_idle_install,
fm68k_reason_idle_remove,
} fm68k_call_reason;
extern M68K_CONTEXT *g_m68kcontext;
/************************/
/* Function definition */
@ -174,15 +147,12 @@ typedef enum
/* General purpose functions */
void fm68k_init(void);
int fm68k_reset(M68K_CONTEXT *ctx);
int fm68k_emulate(M68K_CONTEXT *ctx, int n, fm68k_call_reason reason);
int fm68k_would_interrupt(M68K_CONTEXT *ctx); // to be called from fm68k_emulate()
int fm68k_reset(void);
int fm68k_emulate(int n, int dualcore, int idle_mode);
int fm68k_would_interrupt(void); // to be called from fm68k_emulate()
u32 fm68k_get_pc(const M68K_CONTEXT *ctx);
unsigned fm68k_get_pc(M68K_CONTEXT *context);
// PICODRIVE_HACK
int fm68k_idle_install(void);
int fm68k_idle_remove(void);
#ifdef __cplusplus
}

File diff suppressed because it is too large Load diff

View file

@ -24,7 +24,7 @@
#define FAMEC_CHECK_BRANCHES
#define FAMEC_EXTRA_INLINE
// #define FAMEC_DEBUG
#define FAMEC_NO_GOTOS
// #define FAMEC_NO_GOTOS
#define FAMEC_ADR_BITS 24
// #define FAMEC_FETCHBITS 8
#define FAMEC_DATABITS 8
@ -35,17 +35,7 @@
#define PICODRIVE_HACK
// Options //
#ifndef FAMEC_NO_GOTOS
// computed gotos is a GNU extension
#ifndef __GNUC__
#define FAMEC_NO_GOTOS
#endif
// as of 3.3, clang takes over 3h to compile this in computed goto mode..
#ifdef __clang__
#define FAMEC_NO_GOTOS
#endif
#endif
#undef INLINE
#ifdef _MSC_VER
#define INLINE
@ -60,6 +50,51 @@
#define FAMEC_EXTRA_INLINE INLINE
#endif
#ifdef u8
#undef u8
#endif
#ifdef s8
#undef s8
#endif
#ifdef u16
#undef u16
#endif
#ifdef s16
#undef s16
#endif
#ifdef u32
#undef u32
#endif
#ifdef s32
#undef s32
#endif
#ifdef uptr
#undef uptr
#endif
#define u8 unsigned char
#define s8 signed char
#define u16 unsigned short
#define s16 signed short
#define u32 unsigned int
#define s32 signed int
#define uptr unsigned long
/*
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
*/
#ifndef M68K_OK
#define M68K_OK 0
#endif
@ -183,29 +218,21 @@
// internals core macros
/////////////////////////
// helper macros
#define BITCOUNT(r,v) \
(r = (v) - (((v)>>1)&0x55555555), r = (r&0x33333333) + ((r>>2)&0x33333333), \
r = (((r + (r>>4))&0x0f0f0f0f) * 0x01010101)>>24)
#define DREG(X) (m68kcontext.dreg[(X)].D)
#define DREGu32(X) (m68kcontext.dreg[(X)].D)
#define DREGs32(X) (m68kcontext.dreg[(X)].SD)
#define DREGu16(X) (m68kcontext.dreg[(X)].W)
#define DREGs16(X) (m68kcontext.dreg[(X)].SW)
#define DREGu8(X) (m68kcontext.dreg[(X)].B)
#define DREGs8(X) (m68kcontext.dreg[(X)].SB)
#define XB MEM_LE4(0)
#define XW MEM_LE2(0)
#define AREG(X) (m68kcontext.areg[(X)].D)
#define AREGu32(X) (m68kcontext.areg[(X)].D)
#define AREGs32(X) (m68kcontext.areg[(X)].SD)
#define AREGu16(X) (m68kcontext.areg[(X)].W)
#define AREGs16(X) (m68kcontext.areg[(X)].SW)
#define DREG(X) (ctx->dreg[(X)].D)
#define DREGu32(X) (ctx->dreg[(X)].D)
#define DREGs32(X) (ctx->dreg[(X)].SD)
#define DREGu16(X) (ctx->dreg[(X)].W[XW])
#define DREGs16(X) (ctx->dreg[(X)].SW[XW])
#define DREGu8(X) (ctx->dreg[(X)].B[XB])
#define DREGs8(X) (ctx->dreg[(X)].SB[XB])
#define AREG(X) (ctx->areg[(X)].D)
#define AREGu32(X) (ctx->areg[(X)].D)
#define AREGs32(X) (ctx->areg[(X)].SD)
#define AREGu16(X) (ctx->areg[(X)].W[XW])
#define AREGs16(X) (ctx->areg[(X)].SW[XW])
#define ASP (ctx->asp)
#define ASP (m68kcontext.asp)
#define LSL(A, C) ((A) << (C))
#define LSR(A, C) ((A) >> (C))
@ -228,51 +255,45 @@
#define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C)))
#ifndef FAMEC_NO_GOTOS
#define NEXT { \
#define NEXT \
FETCH_WORD(Opcode); \
goto *JumpTable[Opcode]; \
}
goto *JumpTable[Opcode];
#ifdef FAMEC_ROLL_INLINE
#define RET(A) { \
ctx->io_cycle_counter -= (A); \
if (ctx->io_cycle_counter <= 0) goto famec_Exec_End; \
NEXT \
}
#define RET(A) \
m68kcontext.io_cycle_counter -= (A); \
if (m68kcontext.io_cycle_counter <= 0) goto famec_Exec_End; \
NEXT
#else
#define RET(A) { \
ctx->io_cycle_counter -= (A); \
if (ctx->io_cycle_counter <= 0) goto famec_Exec_End; \
goto famec_Exec; \
}
#define RET(A) \
m68kcontext.io_cycle_counter -= (A); \
if (m68kcontext.io_cycle_counter <= 0) goto famec_Exec_End; \
goto famec_Exec;
#endif
#define RET0() { \
ctx->io_cycle_counter = -6; \
goto famec_End; \
}
#define RET0() \
m68kcontext.io_cycle_counter = -6; \
goto famec_End;
#else
#define NEXT \
do { \
FETCH_WORD(Opcode); \
JumpTable[Opcode](ctx); \
} while (ctx->io_cycle_counter > 0);
do{ \
FETCH_WORD(Opcode); \
JumpTable[Opcode](); \
}while(m68kcontext.io_cycle_counter>0);
#define RET(A) { \
ctx->io_cycle_counter -= (A); \
return; \
}
#define RET(A) \
m68kcontext.io_cycle_counter -= (A); \
return;
#define RET0() { \
ctx->io_cycle_counter = -6; \
return; \
}
#define RET0() \
m68kcontext.io_cycle_counter = -6; \
return;
#endif
#define M68K_PPL (ctx->sr >> 8) & 7
#define M68K_PPL (m68kcontext.sr >> 8) & 7
#define GET_PC \
(u32)((uptr)PC - BasePC)
@ -290,7 +311,7 @@
{ \
u32 pc = A; \
FORCE_ALIGNMENT(pc); \
BasePC = ctx->Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK]; \
BasePC = m68kcontext.Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK]; \
PC = (u16*)((pc & M68K_ADR_MASK) + BasePC); \
}
@ -300,7 +321,7 @@
{ \
u32 pc = A; \
FORCE_ALIGNMENT(pc); \
BasePC = ctx->Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK]; \
BasePC = m68kcontext.Fetch[(pc >> M68K_FETCHSFT) & M68K_FETCHMASK]; \
BasePC -= pc & 0xFF000000; \
PC = (u16*)(pc + BasePC); \
}
@ -315,29 +336,29 @@
// CCnt = io_cycle_counter;
#define READ_BYTE_F(A, D) \
D = ctx->read_byte(A) & 0xFF;
D = m68kcontext.read_byte(A) & 0xFF;
#define READ_WORD_F(A, D) \
D = ctx->read_word(A) & 0xFFFF;
D = m68kcontext.read_word(A) & 0xFFFF;
#define READ_LONG_F(A, D) \
D = ctx->read_long(A);
D = m68kcontext.read_long(A);
#define READSX_LONG_F READ_LONG_F
#define WRITE_LONG_F(A, D) \
ctx->write_long(A, D);
m68kcontext.write_long(A, D);
#define WRITE_LONG_DEC_F(A, D) \
ctx->write_word((A) + 2, (D) & 0xFFFF); \
ctx->write_word((A), (D) >> 16);
m68kcontext.write_word((A) + 2, (D) & 0xFFFF); \
m68kcontext.write_word((A), (D) >> 16);
#define PUSH_32_F(D) \
AREG(7) -= 4; \
ctx->write_long(AREG(7), D);
m68kcontext.write_long(AREG(7), D);
#define POP_32_F(D) \
D = ctx->read_long(AREG(7)); \
D = m68kcontext.read_long(AREG(7)); \
AREG(7) += 4;
#ifndef FAME_BIG_ENDIAN
@ -409,23 +430,23 @@
#endif
#define READSX_BYTE_F(A, D) \
D = (s8)ctx->read_byte(A);
D = (s8)m68kcontext.read_byte(A);
#define READSX_WORD_F(A, D) \
D = (s16)ctx->read_word(A);
D = (s16)m68kcontext.read_word(A);
#define WRITE_BYTE_F(A, D) \
ctx->write_byte(A, D);
m68kcontext.write_byte(A, D);
#define WRITE_WORD_F(A, D) \
ctx->write_word(A, D);
m68kcontext.write_word(A, D);
#define PUSH_16_F(D) \
ctx->write_word(AREG(7) -= 2, D); \
m68kcontext.write_word(AREG(7) -= 2, D); \
#define POP_16_F(D) \
D = (u16)ctx->read_word(AREG(7)); \
D = (u16)m68kcontext.read_word(AREG(7)); \
AREG(7) += 2;
#define GET_CCR \
@ -470,17 +491,17 @@
#endif
#define CHECK_INT_TO_JUMP(CLK) \
if (interrupt_chk__(ctx)) \
if (interrupt_chk__()) \
{ \
cycles_needed=ctx->io_cycle_counter-(CLK); \
ctx->io_cycle_counter=(CLK); \
cycles_needed=m68kcontext.io_cycle_counter-(CLK); \
m68kcontext.io_cycle_counter=(CLK); \
}
#ifdef FAMEC_CHECK_BRANCHES
#ifdef FAMEC_NO_GOTOS
#define CHECK_BRANCH_EXCEPTION_GOTO_END ctx->io_cycle_counter=0; return;
#define CHECK_BRANCH_EXCEPTION_GOTO_END m68kcontext.io_cycle_counter=0; return;
#else
#define CHECK_BRANCH_EXCEPTION_GOTO_END goto famec_Exec_End;
#endif
@ -489,8 +510,8 @@
if ((_PC_)&1) \
{ \
u32 new_PC, pr_PC=GET_PC; \
ctx->execinfo |= FM68K_EMULATE_GROUP_0; \
new_PC = execute_exception_group_0(ctx, M68K_ADDRESS_ERROR_EX, 0, pr_PC, 0x12 ); \
m68kcontext.execinfo |= FM68K_EMULATE_GROUP_0; \
new_PC = execute_exception_group_0(M68K_ADDRESS_ERROR_EX, 0, pr_PC, 0x12 ); \
SET_PC(new_PC); \
CHECK_BRANCH_EXCEPTION_GOTO_END \
}
@ -498,33 +519,38 @@
#define CHECK_BRANCH_EXCEPTION(_PC_)
#endif
#ifdef FAMEC_NO_GOTOS
#define Opcode ctx->Opcode
#define cycles_needed ctx->cycles_needed
#define PC ctx->PC
#define BasePC ctx->BasePC
#define flag_C ctx->flag_C
#define flag_V ctx->flag_V
#define flag_NotZ ctx->flag_NotZ
#define flag_N ctx->flag_N
#define flag_X ctx->flag_X
#endif
#define flag_T ctx->flag_T
#define flag_S ctx->flag_S
#define flag_I ctx->flag_I
// global variable
///////////////////
/* Current CPU context */
M68K_CONTEXT *g_m68kcontext;
#define m68kcontext (*g_m68kcontext)
#ifdef FAMEC_NO_GOTOS
#define Opcode m68kcontext.Opcode
#define cycles_needed m68kcontext.cycles_needed
#define PC m68kcontext.PC
#define BasePC m68kcontext.BasePC
#define flag_C m68kcontext.flag_C
#define flag_V m68kcontext.flag_V
#define flag_NotZ m68kcontext.flag_NotZ
#define flag_N m68kcontext.flag_N
#define flag_X m68kcontext.flag_X
#endif
#define flag_T m68kcontext.flag_T
#define flag_S m68kcontext.flag_S
#define flag_I m68kcontext.flag_I
static u32 initialised = 0;
#ifdef PICODRIVE_HACK
extern M68K_CONTEXT PicoCpuFS68k;
extern M68K_CONTEXT PicoCpuFM68k, PicoCpuFS68k;
#endif
/* Custom function handler */
typedef void (*opcode_func)(M68K_CONTEXT *ctx);
typedef void (*opcode_func)(void);
static opcode_func JumpTable[0x10000];
@ -536,13 +562,13 @@ static const s32 exception_cycle_table[256] =
50, // 2: Bus Error
50, // 3: Address Error
34, // 4: Illegal Instruction
34, // 5: Divide by Zero
34, // 6: CHK
38, // 5: Divide by Zero
40, // 6: CHK
34, // 7: TRAPV
34, // 8: Privilege Violation
34, // 9: Trace
34, // 10: Line A
34, // 11: Line F
4, // 10:
4, // 11:
4, // 12: RESERVED
4, // 13: Coprocessor Protocol Violation
4, // 14: Format Error
@ -604,7 +630,6 @@ static const s32 exception_cycle_table[256] =
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
};
static int init_jump_table(void);
/***********************/
/* core main functions */
@ -621,8 +646,8 @@ void fm68k_init(void)
puts("Initializing FAME...");
#endif
if (!initialised)
init_jump_table();
if (!initialised)
fm68k_emulate(0, 0, 0);
#ifdef FAMEC_DEBUG
puts("FAME initialized.");
@ -638,33 +663,33 @@ void fm68k_init(void)
/* M68K_NO_SUP_ADDR_SPACE (2): No se puede resetear porque no hay mapa */
/* de memoria supervisor de extraccion de opcodes */
/******************************************************************************/
int fm68k_reset(M68K_CONTEXT *ctx)
int fm68k_reset(void)
{
if (!initialised)
init_jump_table();
fm68k_emulate(0, 0, 0);
// Si la CPU esta en ejecucion, salir con M68K_RUNNING
if (ctx->execinfo & M68K_RUNNING)
if (m68kcontext.execinfo & M68K_RUNNING)
return M68K_RUNNING;
// Resetear registros
//memset(&ctx->dreg[0], 0, 16*4);
//memset(&m68kcontext.dreg[0], 0, 16*4);
// Resetear interrupts, execinfo y ASP
ctx->interrupts[0] = 0;
ctx->execinfo = 0;
m68kcontext.interrupts[0] = 0;
m68kcontext.execinfo = 0;
ASP = 0;
// Fijar registro de estado
ctx->sr = (ctx->sr & 0xff) | 0x2700;
m68kcontext.sr = (m68kcontext.sr & 0xff) | 0x2700;
// Obtener puntero de pila inicial y PC
AREG(7) = ctx->read_long(0);
ctx->pc = ctx->read_long(4);
AREG(7) = m68kcontext.read_long(0);
m68kcontext.pc = m68kcontext.read_long(4);
#ifdef FAMEC_DEBUG
puts("Reset 68k done!\n");
printf("PC = 0x%08X\n",ctx->pc);
printf("PC = 0x%08X\n",m68kcontext.pc);
#endif
return M68K_OK;
@ -676,40 +701,37 @@ int fm68k_reset(M68K_CONTEXT *ctx)
/* No recibe parametros */
/* Retorna 68k PC */
/****************************************************************************/
u32 fm68k_get_pc(const M68K_CONTEXT *ctx)
u32 fm68k_get_pc(M68K_CONTEXT *context)
{
#ifdef FAMEC_NO_GOTOS
return (ctx->execinfo & M68K_RUNNING)?(uptr)PC-BasePC:ctx->pc;
return (context->execinfo & M68K_RUNNING)?(uptr)PC-BasePC:context->pc;
#else
return ctx->pc; // approximate PC in this mode
return context->pc; // approximate PC in this mode
#endif
}
//////////////////////////
// Chequea las interrupciones y las inicia
static FAMEC_EXTRA_INLINE s32 interrupt_chk__(M68K_CONTEXT *ctx)
static FAMEC_EXTRA_INLINE s32 interrupt_chk__(void)
{
if (ctx->interrupts[0] > flag_I)
return ctx->interrupts[0];
if (m68kcontext.interrupts[0] > flag_I)
return m68kcontext.interrupts[0];
return 0;
}
int fm68k_would_interrupt(M68K_CONTEXT *ctx)
int fm68k_would_interrupt(void)
{
return interrupt_chk__(ctx);
return interrupt_chk__();
}
static FAMEC_EXTRA_INLINE u32 execute_exception(M68K_CONTEXT *ctx, s32 vect, u32 oldPC, u32 oldSR)
static FAMEC_EXTRA_INLINE u32 execute_exception(s32 vect, u32 oldPC, u32 oldSR)
{
u32 newPC;
//u32 oldSR = GET_SR;
ctx->io_cycle_counter -= exception_cycle_table[vect];
#ifdef FAMEC_EMULATE_TRACE
ctx->execinfo &= ~FM68K_EMULATE_TRACE;
#endif
m68kcontext.io_cycle_counter -= exception_cycle_table[vect];
PRE_IO
@ -731,7 +753,6 @@ static FAMEC_EXTRA_INLINE u32 execute_exception(M68K_CONTEXT *ctx, s32 vect, u32
/* adjust SR */
flag_S = M68K_SR_S;
flag_T = 0;
#ifndef FAMEC_32BIT_PC
newPC&=M68K_ADR_MASK
@ -747,12 +768,12 @@ static FAMEC_EXTRA_INLINE u32 execute_exception(M68K_CONTEXT *ctx, s32 vect, u32
return newPC;
}
static FAMEC_EXTRA_INLINE u32 execute_exception_group_0(M68K_CONTEXT *ctx, s32 vect, s32 addr, u16 spec_info, u32 oldSR)
static FAMEC_EXTRA_INLINE u32 execute_exception_group_0(s32 vect, s32 addr, u16 spec_info, u32 oldSR)
{
u32 newPC;
u16 inst_reg = 0;
newPC = execute_exception(ctx, vect, addr, oldSR);
//if (!(ctx->icust_handler && ctx->icust_handler[vect]))
newPC = execute_exception(vect, addr, oldSR);
//if (!(m68kcontext.icust_handler && m68kcontext.icust_handler[vect]))
{
PUSH_16_F(inst_reg);
PUSH_32_F(addr);
@ -764,7 +785,7 @@ static FAMEC_EXTRA_INLINE u32 execute_exception_group_0(M68K_CONTEXT *ctx, s32 v
#ifdef FAMEC_NO_GOTOS
#define OPCODE(N_OP) static void OP_##N_OP(M68K_CONTEXT *ctx)
#define OPCODE(N_OP) static void OP_##N_OP(void)
#define CAST_OP(N_OP) (opcode_func)&OP_##N_OP
#include "famec_opcodes.h"
#endif
@ -773,7 +794,7 @@ static FAMEC_EXTRA_INLINE u32 execute_exception_group_0(M68K_CONTEXT *ctx, s32 v
// main exec function
//////////////////////
int fm68k_emulate(M68K_CONTEXT *ctx, int cycles, fm68k_call_reason reason)
int fm68k_emulate(s32 cycles, int dualcore, int idle_mode)
{
#ifndef FAMEC_NO_GOTOS
u32 Opcode;
@ -785,37 +806,33 @@ int fm68k_emulate(M68K_CONTEXT *ctx, int cycles, fm68k_call_reason reason)
u32 flag_NotZ;
u32 flag_N;
u32 flag_X;
switch (reason)
{
case fm68k_reason_init:
goto init_jump_table;
#ifdef PICODRIVE_HACK
case fm68k_reason_idle_install:
goto idle_install;
case fm68k_reason_idle_remove:
goto idle_remove;
#endif
case fm68k_reason_emulate:
break;
if (!initialised)
{
goto init_jump_table;
}
PC = ctx->PC;
BasePC = ctx->BasePC;
#endif // FAMEC_NO_GOTOS
#ifdef PICODRIVE_HACK
if (dualcore) goto dualcore_mode;
if (idle_mode == 1) goto idle_install;
else if (idle_mode == 2) goto idle_remove;
famec_restart:
#endif
// won't emulate double fault
// if (ctx->execinfo & M68K_FAULTED) return -1;
// if (m68kcontext.execinfo & M68K_FAULTED) return -1;
// Cache PPL
flag_I = M68K_PPL;
if (ctx->execinfo & FM68K_HALTED)
if (m68kcontext.execinfo & FM68K_HALTED)
{
if (interrupt_chk__(ctx) <= 0)
if (interrupt_chk__() <= 0)
{
return cycles;
}
ctx->execinfo &= ~FM68K_HALTED;
m68kcontext.execinfo &= ~FM68K_HALTED;
}
#ifdef FAMEC_DEBUG
@ -823,13 +840,13 @@ int fm68k_emulate(M68K_CONTEXT *ctx, int cycles, fm68k_call_reason reason)
#endif
/* Poner la CPU en estado de ejecucion */
ctx->execinfo |= M68K_RUNNING;
m68kcontext.execinfo |= M68K_RUNNING;
// Cache SR
SET_SR(ctx->sr)
SET_SR(m68kcontext.sr)
// Fijar PC
SET_PC(ctx->pc)
SET_PC(m68kcontext.pc)
#ifdef FAMEC_DEBUG
printf("PC: %p\n",PC);
@ -837,33 +854,33 @@ int fm68k_emulate(M68K_CONTEXT *ctx, int cycles, fm68k_call_reason reason)
#endif
/* guardar ciclos de ejecucion solicitados */
ctx->io_cycle_counter = cycles;
m68kcontext.io_cycle_counter = cycles;
cycles_needed = 0;
#ifdef FAMEC_EMULATE_TRACE
if (!(ctx->execinfo & FM68K_EMULATE_TRACE))
if (!(m68kcontext.execinfo & FM68K_EMULATE_TRACE))
#endif
{
s32 line=interrupt_chk__(ctx);
s32 line=interrupt_chk__();
if (line>0)
{
/* comprobar si hay rutina de acknowledge */
if (ctx->iack_handler != NULL)
ctx->iack_handler(line);
if (m68kcontext.iack_handler != NULL)
m68kcontext.iack_handler(line);
else
ctx->interrupts[0] = 0;
m68kcontext.interrupts[0] = 0;
SET_PC(execute_exception(ctx, line + 0x18, GET_PC, GET_SR));
SET_PC(execute_exception(line + 0x18, GET_PC, GET_SR));
flag_I = (u32)line;
if (ctx->io_cycle_counter <= 0) goto famec_End;
if (m68kcontext.io_cycle_counter <= 0) goto famec_End;
}
#ifdef FAMEC_EMULATE_TRACE
else
if (flag_T)
{
ctx->execinfo |= FM68K_EMULATE_TRACE;
cycles_needed = ctx->io_cycle_counter;
ctx->io_cycle_counter=0;
m68kcontext.execinfo |= FM68K_EMULATE_TRACE;
cycles_needed = m68kcontext.io_cycle_counter;
m68kcontext.io_cycle_counter=0;
}
#endif
}
@ -889,14 +906,15 @@ famec_Exec:
#endif
#ifdef FAMEC_EMULATE_TRACE
if (ctx->execinfo & FM68K_EMULATE_TRACE)
if (m68kcontext.execinfo & FM68K_EMULATE_TRACE)
{
ctx->io_cycle_counter += cycles_needed;
m68kcontext.io_cycle_counter = cycles_needed;
cycles_needed = 0;
ctx->execinfo &= ~FM68K_EMULATE_TRACE;
ctx->execinfo |= FM68K_DO_TRACE;
SET_PC(execute_exception(ctx, M68K_TRACE_EX, GET_PC, GET_SR));
if (ctx->io_cycle_counter > 0)
m68kcontext.execinfo &= ~FM68K_EMULATE_TRACE;
m68kcontext.execinfo |= FM68K_DO_TRACE;
SET_PC(execute_exception(M68K_TRACE_EX, GET_PC, GET_SR));
flag_T=0;
if (m68kcontext.io_cycle_counter > 0)
{
//NEXT
goto famec_Exec;
@ -907,24 +925,24 @@ famec_Exec:
if (cycles_needed != 0)
{
u32 line;
ctx->io_cycle_counter += cycles_needed;
m68kcontext.io_cycle_counter = cycles_needed;
cycles_needed = 0;
//if (ctx->io_cycle_counter <= 0) goto famec_End;
line=interrupt_chk__(ctx);
if (m68kcontext.io_cycle_counter <= 0) goto famec_End;
line=interrupt_chk__();
if (line>0)
{
if (ctx->iack_handler != NULL)
ctx->iack_handler(line);
if (m68kcontext.iack_handler != NULL)
m68kcontext.iack_handler(line);
else
ctx->interrupts[0] = 0;
m68kcontext.interrupts[0] = 0;
SET_PC(execute_exception(ctx, line + 0x18, GET_PC, GET_SR));
SET_PC(execute_exception(line + 0x18, GET_PC, GET_SR));
flag_I = (u32)line;
}
#ifdef FAMEC_EMULATE_TRACE
if (!(flag_T))
#endif
if (ctx->io_cycle_counter > 0)
if (m68kcontext.io_cycle_counter > 0)
{
//NEXT
goto famec_Exec;
@ -932,31 +950,72 @@ famec_Exec:
}
famec_End:
ctx->sr = GET_SR;
ctx->pc = GET_PC;
#ifndef FAMEC_NO_GOTOS
ctx->PC = PC;
ctx->BasePC = BasePC;
#endif
m68kcontext.sr = GET_SR;
m68kcontext.pc = GET_PC;
ctx->execinfo &= ~M68K_RUNNING;
m68kcontext.execinfo &= ~M68K_RUNNING;
#ifdef FAMEC_DEBUG
printf("En really end...\n");
printf("PC: %p\n",PC);
printf("BasePC: 0x%08x\n",BasePC);
printf("pc: 0x%08x\n",ctx->pc);
printf("pc: 0x%08x\n",m68kcontext.pc);
#endif
return cycles - ctx->io_cycle_counter;
#ifdef PICODRIVE_HACK
if (!dualcore)
#endif
return cycles - m68kcontext.io_cycle_counter;
#ifdef PICODRIVE_HACK
dualcore_mode:
while (1)
{
extern int SekCycleAim, SekCycleCnt, SekCycleAimS68k, SekCycleCntS68k;
#define PS_STEP_M68K ((488<<16)/20) // ~24
if (dualcore == 1)
{
dualcore = (488<<16); // ~ cycn in Pico.c
// adjust for first iteration
g_m68kcontext = &PicoCpuFS68k;
cycles = m68kcontext.io_cycle_counter = 0;
}
if (g_m68kcontext == &PicoCpuFS68k)
{
SekCycleCntS68k += cycles - m68kcontext.io_cycle_counter;
// end?
dualcore -= PS_STEP_M68K;
if (dualcore < 0) return 0;
// become main 68k
g_m68kcontext = &PicoCpuFM68k;
if ((cycles = SekCycleAim-SekCycleCnt-(dualcore>>16)) > 0)
{
if ((m68kcontext.execinfo & FM68K_HALTED) && m68kcontext.interrupts[0] <= (M68K_PPL))
SekCycleCnt += cycles; // halted
else goto famec_restart;
//else { printf("go main %i\n", cycles); goto famec_restart; }
}
cycles = m68kcontext.io_cycle_counter = 0;
}
if (g_m68kcontext == &PicoCpuFM68k)
{
int cycn_s68k = (dualcore + dualcore/2 + dualcore/8) >> 16;
SekCycleCnt += cycles - m68kcontext.io_cycle_counter;
// become sub 68k
g_m68kcontext = &PicoCpuFS68k;
if ((cycles = SekCycleAimS68k-SekCycleCntS68k-cycn_s68k) > 0)
{
if ((m68kcontext.execinfo & FM68K_HALTED) && m68kcontext.interrupts[0] <= (M68K_PPL))
SekCycleCntS68k += cycles; // halted
else goto famec_restart;
}
cycles = m68kcontext.io_cycle_counter = 0;
}
}
#endif
#ifndef FAMEC_NO_GOTOS
init_jump_table:
#else
}
static int init_jump_table(void)
#endif
{
u32 i, j;
@ -4986,12 +5045,7 @@ static int init_jump_table(void)
JumpTable[fake_op_base] = JumpTable[fake_op_base|0x0200] = CAST_OP(0x4AFC); \
JumpTable[real_op] = CAST_OP(normal_handler)
#ifndef FAMEC_NO_GOTOS
idle_install:
#else
int fm68k_idle_install(void)
#endif
{
// printf("install..\n");
INSTALL_IDLE(0x71fa, 0x66fa, idle_detector_bcc8, 0x6601_idle, 0x6601);
INSTALL_IDLE(0x71f8, 0x66f8, idle_detector_bcc8, 0x6601_idle, 0x6601);
@ -5004,14 +5058,8 @@ int fm68k_idle_install(void)
INSTALL_IDLE(0x7dfe, 0x60fe, idle_detector_bcc8, 0x6001_idle, 0x6001);
INSTALL_IDLE(0x7dfc, 0x60fc, idle_detector_bcc8, 0x6001_idle, 0x6001);
return 0;
}
#ifndef FAMEC_NO_GOTOS
idle_remove:
#else
int fm68k_idle_remove(void)
#endif
{
// printf("remove..\n");
UNDO_IDLE(0x71fa, 0x66fa, 0x6601);
UNDO_IDLE(0x71f8, 0x66f8, 0x6601);
@ -5024,26 +5072,9 @@ int fm68k_idle_remove(void)
UNDO_IDLE(0x7dfe, 0x60fe, 0x6001);
UNDO_IDLE(0x7dfc, 0x60fc, 0x6001);
return 0;
}
#endif // PICODRIVE_HACK
#ifndef FAMEC_NO_GOTOS
}
static int init_jump_table(void)
{
return fm68k_emulate(NULL, 0, fm68k_reason_init);
}
#ifdef PICODRIVE_HACK
int fm68k_idle_install(void)
{
return fm68k_emulate(NULL, 0, fm68k_reason_idle_install);
}
int fm68k_idle_remove(void)
{
return fm68k_emulate(NULL, 0, fm68k_reason_idle_remove);
}
#endif
#endif // FAMEC_NO_GOTOS
}
void *get_jumptab(void) { return JumpTable; }

File diff suppressed because it is too large Load diff

View file

@ -257,62 +257,11 @@ void m68ki_build_opcode_table(void)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
M68KMAKE_OPCODE_HANDLER_HEADER
#include <stdlib.h>
#include "m68kcpu.h"
extern void m68040_fpu_op0(void);
extern void m68040_fpu_op1(void);
/* Count non-0 bits */
INLINE int m68ki_bit_count(uint32 arg)
{
arg = arg - ((arg>>1)&0x55555555);
arg = (arg&0x33333333) + ((arg>>2)&0x33333333);
return (((arg + (arg>>4))&0x0f0f0f0f) * 0x01010101) >> 24;
}
INLINE int m68ki_mulu_cycles(uint32 arg)
{
if (CPU_TYPE_IS_000(CPU_TYPE))
return m68ki_bit_count(arg) * 2;
else if (CPU_TYPE_IS_010(CPU_TYPE))
return m68ki_bit_count(arg); /* guesswork */
else
return m68ki_bit_count(arg) / 2; /* guesswork */
}
INLINE int m68ki_muls_cycles(sint32 arg)
{
if (CPU_TYPE_IS_000(CPU_TYPE))
return m68ki_bit_count(arg ^ (arg<<1)) * 2;
else if (CPU_TYPE_IS_010(CPU_TYPE))
return m68ki_bit_count(arg ^ (arg<<1)); /* guesswork */
else
return m68ki_bit_count(arg ^ (arg<<1)) / 2; /* guesswork */
}
INLINE int m68ki_divu_cycles(uint32 arg)
{
/* approximation only. Doesn't factor in shorter cycles by carry */
if (CPU_TYPE_IS_000(CPU_TYPE))
return 128 - m68ki_bit_count(arg) * 2;
else if (CPU_TYPE_IS_010(CPU_TYPE))
return 96; /* guesswork */
else
return 32; /* guesswork */
}
INLINE int m68ki_divs_cycles(uint32 scyc, sint32 arg)
{
/* approximation only. Doesn't factor in shorter cycles by carry */
if (CPU_TYPE_IS_000(CPU_TYPE))
return 128 - m68ki_bit_count(abs(arg)) * 2 + scyc*2 + 8;
else if (CPU_TYPE_IS_010(CPU_TYPE))
return 96 + scyc*2 + 8; /* guesswork */
else
return 32 + scyc + 4; /* guesswork */
}
/* ======================================================================== */
/* ========================= INSTRUCTION HANDLERS ========================= */
/* ======================================================================== */
@ -440,7 +389,7 @@ addi 32 . . 0000011010...... A+-DXWL... U U U U 20 20 4 4
addq 8 . d 0101...000000... .......... U U U U 4 4 2 2
addq 8 . . 0101...000...... A+-DXWL... U U U U 8 8 4 4
addq 16 . d 0101...001000... .......... U U U U 4 4 2 2
addq 16 . a 0101...001001... .......... U U U U 8 8 2 2
addq 16 . a 0101...001001... .......... U U U U 4 4 2 2
addq 16 . . 0101...001...... A+-DXWL... U U U U 8 8 4 4
addq 32 . d 0101...010000... .......... U U U U 8 8 2 2
addq 32 . a 0101...010001... .......... U U U U 8 8 2 2
@ -469,7 +418,7 @@ andi 8 . d 0000001000000... .......... U U U U 8 8 2 2
andi 8 . . 0000001000...... A+-DXWL... U U U U 12 12 4 4
andi 16 . d 0000001001000... .......... U U U U 8 8 2 2
andi 16 . . 0000001001...... A+-DXWL... U U U U 12 12 4 4
andi 32 . d 0000001010000... .......... U U U U 16 14 2 2
andi 32 . d 0000001010000... .......... U U U U 14 14 2 2
andi 32 . . 0000001010...... A+-DXWL... U U U U 20 20 4 4
asr 8 s . 1110...000000... .......... U U U U 6 6 6 6
asr 16 s . 1110...001000... .......... U U U U 6 6 6 6
@ -489,13 +438,13 @@ bcc 8 . . 0110............ .......... U U U U 10 10 6 6
bcc 16 . . 0110....00000000 .......... U U U U 10 10 6 6
bcc 32 . . 0110....11111111 .......... U U U U 10 10 6 6
bchg 8 r . 0000...101...... A+-DXWL... U U U U 8 8 4 4
bchg 32 r d 0000...101000... .......... U U U U 6 6 4 4
bchg 32 r d 0000...101000... .......... U U U U 8 8 4 4
bchg 8 s . 0000100001...... A+-DXWL... U U U U 12 12 4 4
bchg 32 s d 0000100001000... .......... U U U U 10 10 4 4
bclr 8 r . 0000...110...... A+-DXWL... U U U U 8 8 4 4
bclr 32 r d 0000...110000... .......... U U U U 8 8 4 4
bchg 32 s d 0000100001000... .......... U U U U 12 12 4 4
bclr 8 r . 0000...110...... A+-DXWL... U U U U 8 10 4 4
bclr 32 r d 0000...110000... .......... U U U U 10 10 4 4
bclr 8 s . 0000100010...... A+-DXWL... U U U U 12 12 4 4
bclr 32 s d 0000100010000... .......... U U U U 12 12 4 4
bclr 32 s d 0000100010000... .......... U U U U 14 14 4 4
bfchg 32 . d 1110101011000... .......... . . U U . . 12 12 timing not quite correct
bfchg 32 . . 1110101011...... A..DXWL... . . U U . . 20 20
bfclr 32 . d 1110110011000... .......... . . U U . . 12 12
@ -516,10 +465,10 @@ bkpt 0 . . 0100100001001... .......... . U U U . 10 10 10
bra 8 . . 01100000........ .......... U U U U 10 10 10 10
bra 16 . . 0110000000000000 .......... U U U U 10 10 10 10
bra 32 . . 0110000011111111 .......... U U U U 10 10 10 10
bset 32 r d 0000...111000... .......... U U U U 6 6 4 4
bset 32 r d 0000...111000... .......... U U U U 8 8 4 4
bset 8 r . 0000...111...... A+-DXWL... U U U U 8 8 4 4
bset 8 s . 0000100011...... A+-DXWL... U U U U 12 12 4 4
bset 32 s d 0000100011000... .......... U U U U 10 10 4 4
bset 32 s d 0000100011000... .......... U U U U 12 12 4 4
bsr 8 . . 01100001........ .......... U U U U 18 18 7 7
bsr 16 . . 0110000100000000 .......... U U U U 18 18 7 7
bsr 32 . . 0110000111111111 .......... U U U U 18 18 7 7
@ -533,8 +482,8 @@ cas 16 . . 0000110011...... A+-DXWL... . . U U . . 12 12
cas 32 . . 0000111011...... A+-DXWL... . . U U . . 12 12
cas2 16 . . 0000110011111100 .......... . . U U . . 12 12
cas2 32 . . 0000111011111100 .......... . . U U . . 12 12
chk 16 . d 0100...110000... .......... U U U U 4 2 2 2
chk 16 . . 0100...110...... A+-DXWLdxI U U U U 4 2 2 2
chk 16 . d 0100...110000... .......... U U U U 10 8 8 8
chk 16 . . 0100...110...... A+-DXWLdxI U U U U 10 8 8 8
chk 32 . d 0100...100000... .......... . . U U . . 8 8
chk 32 . . 0100...100...... A+-DXWLdxI . . U U . . 8 8
chk2cmp2 8 . pcdi 0000000011111010 .......... . . U U . . 23 23
@ -592,10 +541,10 @@ cptrapcc 32 . . 1111...001111... .......... . . U . . . 4 .
dbt 16 . . 0101000011001... .......... U U U U 12 12 6 6
dbf 16 . . 0101000111001... .......... U U U U 12 12 6 6
dbcc 16 . . 0101....11001... .......... U U U U 12 12 6 6
divs 16 . d 1000...111000... .......... U U U U 16 16 16 16 cycles depending on operands
divs 16 . . 1000...111...... A+-DXWLdxI U U U U 16 16 16 16 cycles depending on operands
divu 16 . d 1000...011000... .......... U U U U 10 10 10 10 cycles depending on operands
divu 16 . . 1000...011...... A+-DXWLdxI U U U U 10 10 10 10 cycles depending on operands
divs 16 . d 1000...111000... .......... U U U U 158 122 56 56
divs 16 . . 1000...111...... A+-DXWLdxI U U U U 158 122 56 56
divu 16 . d 1000...011000... .......... U U U U 140 108 44 44
divu 16 . . 1000...011...... A+-DXWLdxI U U U U 140 108 44 44
divl 32 . d 0100110001000... .......... . . U U . . 84 84
divl 32 . . 0100110001...... A+-DXWLdxI . . U U . . 84 84
eor 8 . d 1011...100000... .......... U U U U 4 4 2 2
@ -747,10 +696,10 @@ moves 8 . . 0000111000...... A+-DXWL... . S S S . 14 5 5
moves 16 . . 0000111001...... A+-DXWL... . S S S . 14 5 5
moves 32 . . 0000111010...... A+-DXWL... . S S S . 16 5 5
move16 32 . . 1111011000100... .......... . . . U . . . 4 TODO: correct timing
muls 16 . d 1100...111000... .......... U U U U 38 28 20 20 cycles depending on operands
muls 16 . . 1100...111...... A+-DXWLdxI U U U U 38 28 20 20 cycles depending on operands
mulu 16 . d 1100...011000... .......... U U U U 38 26 20 20 cycles depending on operands
mulu 16 . . 1100...011...... A+-DXWLdxI U U U U 38 26 20 20 cycles depending on operands
muls 16 . d 1100...111000... .......... U U U U 54 32 27 27
muls 16 . . 1100...111...... A+-DXWLdxI U U U U 54 32 27 27
mulu 16 . d 1100...011000... .......... U U U U 54 30 27 27
mulu 16 . . 1100...011...... A+-DXWLdxI U U U U 54 30 27 27
mull 32 . d 0100110000000... .......... . . U U . . 43 43
mull 32 . . 0100110000...... A+-DXWLdxI . . U U . . 43 43
nbcd 8 . d 0100100000000... .......... U U U U 6 6 6 6
@ -886,7 +835,7 @@ subx 16 mm . 1001...101001... .......... U U U U 18 18 12 12
subx 32 mm . 1001...110001... .......... U U U U 30 30 12 12
swap 32 . . 0100100001000... .......... U U U U 4 4 4 4
tas 8 . d 0100101011000... .......... U U U U 4 4 4 4
tas 8 . . 0100101011...... A+-DXWL... U U U U 10 10 8 8
tas 8 . . 0100101011...... A+-DXWL... U U U U 14 14 12 12
trap 0 . . 010011100100.... .......... U U U U 4 4 4 4
trapt 0 . . 0101000011111100 .......... . . U U . . 4 4
trapt 16 . . 0101000011111010 .......... . . U U . . 6 6
@ -969,15 +918,13 @@ M68KMAKE_OP(abcd, 8, rr, .)
uint src = DY;
uint dst = *r_dst;
uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
uint corf = 0;
if(res > 9)
corf = 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_V = ~res; /* Undefined V behavior */
res += corf;
FLAG_X = FLAG_C = (res > 0x9f) << 8;
if(res > 9)
res += 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_X = FLAG_C = (res > 0x99) << 8;
if(FLAG_C)
res -= 0xa0;
@ -997,15 +944,13 @@ M68KMAKE_OP(abcd, 8, mm, ax7)
uint ea = EA_A7_PD_8();
uint dst = m68ki_read_8(ea);
uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
uint corf = 0;
if(res > 9)
corf = 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_V = ~res; /* Undefined V behavior */
res += corf;
FLAG_X = FLAG_C = (res > 0x9f) << 8;
if(res > 9)
res += 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_X = FLAG_C = (res > 0x99) << 8;
if(FLAG_C)
res -= 0xa0;
@ -1025,15 +970,13 @@ M68KMAKE_OP(abcd, 8, mm, ay7)
uint ea = EA_AX_PD_8();
uint dst = m68ki_read_8(ea);
uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
uint corf = 0;
if(res > 9)
corf = 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_V = ~res; /* Undefined V behavior */
res += corf;
FLAG_X = FLAG_C = (res > 0x9f) << 8;
if(res > 9)
res += 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_X = FLAG_C = (res > 0x99) << 8;
if(FLAG_C)
res -= 0xa0;
@ -1053,15 +996,13 @@ M68KMAKE_OP(abcd, 8, mm, axy7)
uint ea = EA_A7_PD_8();
uint dst = m68ki_read_8(ea);
uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
uint corf = 0;
if(res > 9)
corf = 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_V = ~res; /* Undefined V behavior */
res += corf;
FLAG_X = FLAG_C = (res > 0x9f) << 8;
if(res > 9)
res += 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_X = FLAG_C = (res > 0x99) << 8;
if(FLAG_C)
res -= 0xa0;
@ -1081,15 +1022,13 @@ M68KMAKE_OP(abcd, 8, mm, .)
uint ea = EA_AX_PD_8();
uint dst = m68ki_read_8(ea);
uint res = LOW_NIBBLE(src) + LOW_NIBBLE(dst) + XFLAG_AS_1();
uint corf = 0;
if(res > 9)
corf = 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_V = ~res; /* Undefined V behavior */
res += corf;
FLAG_X = FLAG_C = (res > 0x9f) << 8;
if(res > 9)
res += 6;
res += HIGH_NIBBLE(src) + HIGH_NIBBLE(dst);
FLAG_X = FLAG_C = (res > 0x99) << 8;
if(FLAG_C)
res -= 0xa0;
@ -2383,8 +2322,6 @@ M68KMAKE_OP(bchg, 32, r, d)
uint* r_dst = &DY;
uint mask = 1 << (DX & 0x1f);
if(CPU_TYPE_IS_010_LESS(CPU_TYPE) && mask >= 0x10000)
USE_CYCLES(2);
FLAG_Z = *r_dst & mask;
*r_dst ^= mask;
}
@ -2406,8 +2343,6 @@ M68KMAKE_OP(bchg, 32, s, d)
uint* r_dst = &DY;
uint mask = 1 << (OPER_I_8() & 0x1f);
if(CPU_TYPE_IS_010_LESS(CPU_TYPE) && mask >= 0x10000)
USE_CYCLES(2);
FLAG_Z = *r_dst & mask;
*r_dst ^= mask;
}
@ -2429,8 +2364,6 @@ M68KMAKE_OP(bclr, 32, r, d)
uint* r_dst = &DY;
uint mask = 1 << (DX & 0x1f);
if(CPU_TYPE_IS_010_LESS(CPU_TYPE) && mask >= 0x10000)
USE_CYCLES(2);
FLAG_Z = *r_dst & mask;
*r_dst &= ~mask;
}
@ -2452,8 +2385,6 @@ M68KMAKE_OP(bclr, 32, s, d)
uint* r_dst = &DY;
uint mask = 1 << (OPER_I_8() & 0x1f);
if(CPU_TYPE_IS_010_LESS(CPU_TYPE) && mask >= 0x10000)
USE_CYCLES(2);
FLAG_Z = *r_dst & mask;
*r_dst &= ~mask;
}
@ -3241,8 +3172,6 @@ M68KMAKE_OP(bset, 32, r, d)
uint* r_dst = &DY;
uint mask = 1 << (DX & 0x1f);
if(CPU_TYPE_IS_010_LESS(CPU_TYPE) && mask >= 0x10000)
USE_CYCLES(2);
FLAG_Z = *r_dst & mask;
*r_dst |= mask;
}
@ -3264,8 +3193,6 @@ M68KMAKE_OP(bset, 32, s, d)
uint* r_dst = &DY;
uint mask = 1 << (OPER_I_8() & 0x1f);
if(CPU_TYPE_IS_010_LESS(CPU_TYPE) && mask >= 0x10000)
USE_CYCLES(2);
FLAG_Z = *r_dst & mask;
*r_dst |= mask;
}
@ -3553,7 +3480,6 @@ M68KMAKE_OP(chk, 16, ., d)
if(src >= 0 && src <= bound)
{
USE_CYCLES(6);
return;
}
FLAG_N = (src < 0)<<7;
@ -3572,7 +3498,6 @@ M68KMAKE_OP(chk, 16, ., .)
if(src >= 0 && src <= bound)
{
USE_CYCLES(6);
return;
}
FLAG_N = (src < 0)<<7;
@ -4552,10 +4477,8 @@ M68KMAKE_OP(divs, 16, ., d)
{
uint* r_dst = &DX;
sint src = MAKE_INT_16(DY);
sint dst = MAKE_INT_32(*r_dst);
sint quotient;
sint remainder;
int cycles;
if(src != 0)
{
@ -4566,21 +4489,12 @@ M68KMAKE_OP(divs, 16, ., d)
FLAG_V = VFLAG_CLEAR;
FLAG_C = CFLAG_CLEAR;
*r_dst = 0;
USE_CYCLES(m68ki_divs_cycles(2, 0));
return;
}
if(abs(dst) >= abs(src<<16))
{
FLAG_V = VFLAG_SET;
USE_CYCLES(2*(dst < 0));
return;
}
quotient = MAKE_INT_32(*r_dst) / src;
remainder = MAKE_INT_32(*r_dst) % src;
quotient = dst / src;
remainder = dst % src;
cycles = m68ki_divs_cycles(2*(dst < 0) + (quotient < 0), quotient);
if(quotient == MAKE_INT_16(quotient))
{
FLAG_Z = quotient;
@ -4588,15 +4502,12 @@ M68KMAKE_OP(divs, 16, ., d)
FLAG_V = VFLAG_CLEAR;
FLAG_C = CFLAG_CLEAR;
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
USE_CYCLES(cycles);
return;
}
FLAG_V = VFLAG_SET;
USE_CYCLES(cycles);
return;
}
m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
ADD_CYCLES(12);
}
@ -4604,10 +4515,8 @@ M68KMAKE_OP(divs, 16, ., .)
{
uint* r_dst = &DX;
sint src = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16);
sint dst = MAKE_INT_32(*r_dst);
sint quotient;
sint remainder;
int cycles;
if(src != 0)
{
@ -4618,21 +4527,12 @@ M68KMAKE_OP(divs, 16, ., .)
FLAG_V = VFLAG_CLEAR;
FLAG_C = CFLAG_CLEAR;
*r_dst = 0;
USE_CYCLES(m68ki_divs_cycles(2, 0));
return;
}
if(abs(dst) >= abs(src<<16))
{
FLAG_V = VFLAG_SET;
USE_CYCLES(2*(dst < 0));
return;
}
quotient = MAKE_INT_32(*r_dst) / src;
remainder = MAKE_INT_32(*r_dst) % src;
quotient = dst / src;
remainder = dst % src;
cycles = m68ki_divs_cycles(2*(dst < 0) + (quotient < 0), quotient);
if(quotient == MAKE_INT_16(quotient))
{
FLAG_Z = quotient;
@ -4640,15 +4540,12 @@ M68KMAKE_OP(divs, 16, ., .)
FLAG_V = VFLAG_CLEAR;
FLAG_C = CFLAG_CLEAR;
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
USE_CYCLES(cycles);
return;
}
FLAG_V = VFLAG_SET;
USE_CYCLES(cycles);
return;
}
m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
ADD_CYCLES(12);
}
@ -4669,14 +4566,12 @@ M68KMAKE_OP(divu, 16, ., d)
FLAG_V = VFLAG_CLEAR;
FLAG_C = CFLAG_CLEAR;
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
USE_CYCLES(m68ki_divu_cycles(quotient));
return;
}
FLAG_V = VFLAG_SET;
return;
}
m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
ADD_CYCLES(6);
}
@ -4697,14 +4592,12 @@ M68KMAKE_OP(divu, 16, ., .)
FLAG_V = VFLAG_CLEAR;
FLAG_C = CFLAG_CLEAR;
*r_dst = MASK_OUT_ABOVE_32(MASK_OUT_ABOVE_16(quotient) | (remainder << 16));
USE_CYCLES(m68ki_divu_cycles(quotient));
return;
}
FLAG_V = VFLAG_SET;
return;
}
m68ki_exception_trap(EXCEPTION_ZERO_DIVIDE);
ADD_CYCLES(6);
}
@ -7597,11 +7490,9 @@ M68KMAKE_OP(move16, 32, ., .)
M68KMAKE_OP(muls, 16, ., d)
{
uint* r_dst = &DX;
uint x = MAKE_INT_16(DY);
uint res = MASK_OUT_ABOVE_32(x * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst)));
uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(DY) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst)));
*r_dst = res;
USE_CYCLES(m68ki_muls_cycles(x));
FLAG_Z = res;
FLAG_N = NFLAG_32(res);
@ -7613,11 +7504,9 @@ M68KMAKE_OP(muls, 16, ., d)
M68KMAKE_OP(muls, 16, ., .)
{
uint* r_dst = &DX;
uint x = MAKE_INT_16(M68KMAKE_GET_OPER_AY_16);
uint res = MASK_OUT_ABOVE_32(x * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst)));
uint res = MASK_OUT_ABOVE_32(MAKE_INT_16(M68KMAKE_GET_OPER_AY_16) * MAKE_INT_16(MASK_OUT_ABOVE_16(*r_dst)));
*r_dst = res;
USE_CYCLES(m68ki_muls_cycles(x));
FLAG_Z = res;
FLAG_N = NFLAG_32(res);
@ -7629,11 +7518,9 @@ M68KMAKE_OP(muls, 16, ., .)
M68KMAKE_OP(mulu, 16, ., d)
{
uint* r_dst = &DX;
uint x = MASK_OUT_ABOVE_16(DY);
uint res = x * MASK_OUT_ABOVE_16(*r_dst);
uint res = MASK_OUT_ABOVE_16(DY) * MASK_OUT_ABOVE_16(*r_dst);
*r_dst = res;
USE_CYCLES(m68ki_mulu_cycles(x));
FLAG_Z = res;
FLAG_N = NFLAG_32(res);
@ -7645,11 +7532,9 @@ M68KMAKE_OP(mulu, 16, ., d)
M68KMAKE_OP(mulu, 16, ., .)
{
uint* r_dst = &DX;
uint x = M68KMAKE_GET_OPER_AY_16;
uint res = x * MASK_OUT_ABOVE_16(*r_dst);
uint res = M68KMAKE_GET_OPER_AY_16 * MASK_OUT_ABOVE_16(*r_dst);
*r_dst = res;
USE_CYCLES(m68ki_mulu_cycles(x));
FLAG_Z = res;
FLAG_N = NFLAG_32(res);
@ -7909,19 +7794,19 @@ M68KMAKE_OP(mull, 32, ., .)
M68KMAKE_OP(nbcd, 8, ., d)
{
uint* r_dst = &DY;
uint dst = MASK_OUT_ABOVE_8(*r_dst);
uint res = -dst - XFLAG_AS_1();
uint dst = *r_dst;
uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1());
if(res != 0)
if(res != 0x9a)
{
FLAG_V = res; /* Undefined V behavior */
FLAG_V = ~res; /* Undefined V behavior */
if(((res|dst) & 0x0f) == 0)
res = (res & 0xf0) + 6;
if((res & 0x0f) == 0xa)
res = (res & 0xf0) + 0x10;
res = MASK_OUT_ABOVE_8(res + 0x9a);
res = MASK_OUT_ABOVE_8(res);
FLAG_V &= ~res; /* Undefined V behavior part II */
FLAG_V &= res; /* Undefined V behavior part II */
*r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
@ -7943,18 +7828,18 @@ M68KMAKE_OP(nbcd, 8, ., .)
{
uint ea = M68KMAKE_GET_EA_AY_8;
uint dst = m68ki_read_8(ea);
uint res = -dst - XFLAG_AS_1();
uint res = MASK_OUT_ABOVE_8(0x9a - dst - XFLAG_AS_1());
if(res != 0)
if(res != 0x9a)
{
FLAG_V = res; /* Undefined V behavior */
FLAG_V = ~res; /* Undefined V behavior */
if(((res|dst) & 0x0f) == 0)
res = (res & 0xf0) + 6;
if((res & 0x0f) == 0xa)
res = (res & 0xf0) + 0x10;
res = MASK_OUT_ABOVE_8(res + 0x9a);
res = MASK_OUT_ABOVE_8(res);
FLAG_V &= ~res; /* Undefined V behavior part II */
FLAG_V &= res; /* Undefined V behavior part II */
m68ki_write_8(ea, MASK_OUT_ABOVE_8(res));
@ -9474,26 +9359,26 @@ M68KMAKE_OP(sbcd, 8, rr, .)
uint src = DY;
uint dst = *r_dst;
uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
uint corf = 0;
if(res > 0xf)
corf = 6;
// FLAG_V = ~res; /* Undefined V behavior */
FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to assume cleared. */
if(res > 9)
res -= 6;
res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
FLAG_V = res; /* Undefined V behavior */
if(res > 0xff)
if(res > 0x99)
{
res += 0xa0;
FLAG_X = FLAG_C = CFLAG_SET;
FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
}
else if(res < corf)
FLAG_X = FLAG_C = CFLAG_SET;
else
FLAG_X = FLAG_C = 0;
FLAG_N = FLAG_X = FLAG_C = 0;
res = MASK_OUT_ABOVE_8(res - corf);
res = MASK_OUT_ABOVE_8(res);
FLAG_V &= ~res; /* Undefined V behavior part II */
FLAG_N = NFLAG_8(res); /* Undefined N behavior */
// FLAG_V &= res; /* Undefined V behavior part II */
// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
FLAG_Z |= res;
*r_dst = MASK_OUT_BELOW_8(*r_dst) | res;
@ -9506,26 +9391,26 @@ M68KMAKE_OP(sbcd, 8, mm, ax7)
uint ea = EA_A7_PD_8();
uint dst = m68ki_read_8(ea);
uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
uint corf = 0;
if(res > 0xf)
corf = 6;
// FLAG_V = ~res; /* Undefined V behavior */
FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */
if(res > 9)
res -= 6;
res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
FLAG_V = res; /* Undefined V behavior */
if(res > 0xff)
if(res > 0x99)
{
res += 0xa0;
FLAG_X = FLAG_C = CFLAG_SET;
FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
}
else if(res < corf)
FLAG_X = FLAG_C = CFLAG_SET;
else
FLAG_X = FLAG_C = 0;
FLAG_N = FLAG_X = FLAG_C = 0;
res = MASK_OUT_ABOVE_8(res - corf);
res = MASK_OUT_ABOVE_8(res);
FLAG_V &= ~res; /* Undefined V behavior part II */
FLAG_N = NFLAG_8(res); /* Undefined N behavior */
// FLAG_V &= res; /* Undefined V behavior part II */
// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
FLAG_Z |= res;
m68ki_write_8(ea, res);
@ -9538,26 +9423,26 @@ M68KMAKE_OP(sbcd, 8, mm, ay7)
uint ea = EA_AX_PD_8();
uint dst = m68ki_read_8(ea);
uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
uint corf = 0;
if(res > 0xf)
corf = 6;
// FLAG_V = ~res; /* Undefined V behavior */
FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */
if(res > 9)
res -= 6;
res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
FLAG_V = res; /* Undefined V behavior */
if(res > 0xff)
if(res > 0x99)
{
res += 0xa0;
FLAG_X = FLAG_C = CFLAG_SET;
FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
}
else if(res < corf)
FLAG_X = FLAG_C = CFLAG_SET;
else
FLAG_X = FLAG_C = 0;
FLAG_N = FLAG_X = FLAG_C = 0;
res = MASK_OUT_ABOVE_8(res - corf);
res = MASK_OUT_ABOVE_8(res);
FLAG_V &= ~res; /* Undefined V behavior part II */
FLAG_N = NFLAG_8(res); /* Undefined N behavior */
// FLAG_V &= res; /* Undefined V behavior part II */
// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
FLAG_Z |= res;
m68ki_write_8(ea, res);
@ -9570,26 +9455,26 @@ M68KMAKE_OP(sbcd, 8, mm, axy7)
uint ea = EA_A7_PD_8();
uint dst = m68ki_read_8(ea);
uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
uint corf = 0;
if(res > 0xf)
corf = 6;
// FLAG_V = ~res; /* Undefined V behavior */
FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */
if(res > 9)
res -= 6;
res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
FLAG_V = res; /* Undefined V behavior */
if(res > 0xff)
if(res > 0x99)
{
res += 0xa0;
FLAG_X = FLAG_C = CFLAG_SET;
FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
}
else if(res < corf)
FLAG_X = FLAG_C = CFLAG_SET;
else
FLAG_X = FLAG_C = 0;
FLAG_N = FLAG_X = FLAG_C = 0;
res = MASK_OUT_ABOVE_8(res - corf);
res = MASK_OUT_ABOVE_8(res);
FLAG_V &= ~res; /* Undefined V behavior part II */
FLAG_N = NFLAG_8(res); /* Undefined N behavior */
// FLAG_V &= res; /* Undefined V behavior part II */
// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
FLAG_Z |= res;
m68ki_write_8(ea, res);
@ -9602,26 +9487,26 @@ M68KMAKE_OP(sbcd, 8, mm, .)
uint ea = EA_AX_PD_8();
uint dst = m68ki_read_8(ea);
uint res = LOW_NIBBLE(dst) - LOW_NIBBLE(src) - XFLAG_AS_1();
uint corf = 0;
if(res > 0xf)
corf = 6;
// FLAG_V = ~res; /* Undefined V behavior */
FLAG_V = VFLAG_CLEAR; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to return zero. */
if(res > 9)
res -= 6;
res += HIGH_NIBBLE(dst) - HIGH_NIBBLE(src);
FLAG_V = res; /* Undefined V behavior */
if(res > 0xff)
if(res > 0x99)
{
res += 0xa0;
FLAG_X = FLAG_C = CFLAG_SET;
FLAG_N = NFLAG_SET; /* Undefined in Motorola's M68000PM/AD rev.1 and safer to follow carry. */
}
else if(res < corf)
FLAG_X = FLAG_C = CFLAG_SET;
else
FLAG_X = FLAG_C = 0;
FLAG_N = FLAG_X = FLAG_C = 0;
res = MASK_OUT_ABOVE_8(res - corf);
res = MASK_OUT_ABOVE_8(res);
FLAG_V &= ~res; /* Undefined V behavior part II */
FLAG_N = NFLAG_8(res); /* Undefined N behavior */
// FLAG_V &= res; /* Undefined V behavior part II */
// FLAG_N = NFLAG_8(res); /* Undefined N behavior */
FLAG_Z |= res;
m68ki_write_8(ea, res);

View file

@ -43,7 +43,7 @@ extern void m68040_fpu_op1(void);
/* ================================= DATA ================================= */
/* ======================================================================== */
//int m68ki_initial_cycles;
int m68ki_initial_cycles;
//int m68ki_remaining_cycles = 0; /* Number of clocks remaining */
uint m68ki_tracing = 0;
uint m68ki_address_space;
@ -133,13 +133,13 @@ uint8 m68ki_exception_cycle_table[4][256] =
50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */
34, /* 4: Illegal Instruction */
34, /* 5: Divide by Zero -- ASG: changed from 42 */
34, /* 6: CHK -- ASG: chanaged from 44 */
38, /* 5: Divide by Zero -- ASG: changed from 42 */
40, /* 6: CHK -- ASG: chanaged from 44 */
34, /* 7: TRAPV */
34, /* 8: Privilege Violation */
34, /* 9: Trace */
34, /* 10: 1010 */
34, /* 11: 1111 */
4, /* 10: 1010 */
4, /* 11: 1111 */
4, /* 12: RESERVED */
4, /* 13: Coprocessor Protocol Violation (unemulated) */
4, /* 14: Format Error */
@ -206,13 +206,13 @@ uint8 m68ki_exception_cycle_table[4][256] =
126, /* 2: Bus Error (unemulated) */
126, /* 3: Address Error (unemulated) */
38, /* 4: Illegal Instruction */
38, /* 5: Divide by Zero */
38, /* 6: CHK */
44, /* 5: Divide by Zero */
44, /* 6: CHK */
34, /* 7: TRAPV */
38, /* 8: Privilege Violation */
38, /* 9: Trace */
38, /* 10: 1010 */
38, /* 11: 1111 */
4, /* 10: 1010 */
4, /* 11: 1111 */
4, /* 12: RESERVED */
4, /* 13: Coprocessor Protocol Violation (unemulated) */
4, /* 14: Format Error */
@ -279,8 +279,8 @@ uint8 m68ki_exception_cycle_table[4][256] =
50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */
20, /* 4: Illegal Instruction */
34, /* 5: Divide by Zero */
34, /* 6: CHK */
38, /* 5: Divide by Zero */
40, /* 6: CHK */
20, /* 7: TRAPV */
34, /* 8: Privilege Violation */
25, /* 9: Trace */
@ -352,8 +352,8 @@ uint8 m68ki_exception_cycle_table[4][256] =
50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */
20, /* 4: Illegal Instruction */
34, /* 5: Divide by Zero */
34, /* 6: CHK */
38, /* 5: Divide by Zero */
40, /* 6: CHK */
20, /* 7: TRAPV */
34, /* 8: Privilege Violation */
25, /* 9: Trace */
@ -787,12 +787,12 @@ void m68k_set_cpu_type(unsigned int cpu_type)
/* ASG: removed per-instruction interrupt checks */
int m68k_execute(int num_cycles)
{
// notaz
m68ki_check_interrupts();
/* Make sure we're not stopped */
if(!CPU_STOPPED)
{
// notaz
m68ki_check_interrupts();
/* Set our pool of clock cycles available */
SET_CYCLES(num_cycles);
m68ki_initial_cycles = num_cycles;
@ -808,7 +808,7 @@ int m68k_execute(int num_cycles)
// notaz
m68ki_trace_t1();
while(GET_CYCLES() > 0)
while(GET_CYCLES() >= 0)
// do
{
/* Set tracing accodring to T1. (T0 is done inside instruction) */
@ -828,21 +828,19 @@ int m68k_execute(int num_cycles)
m68ki_instruction_jump_table[REG_IR]();
USE_CYCLES(CYC_INSTRUCTION[REG_IR]); // moving this up may cause a deadlock
/* ASG: update cycles */
USE_CYCLES(CPU_INT_CYCLES);
CPU_INT_CYCLES = 0;
/* Trace m68k_exception, if necessary */
m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
m68ki_trace_t1(); /* notaz */
m68ki_cpu_p->not_polling = 1;
} // while(GET_CYCLES() > 0); // notaz
/* set previous PC to current PC for the next entry into the loop */
REG_PPC = REG_PC;
/* ASG: update cycles */
USE_CYCLES(CPU_INT_CYCLES);
CPU_INT_CYCLES = 0;
/* return how many clocks we used */
return m68ki_initial_cycles - GET_CYCLES();
}

View file

@ -27,11 +27,14 @@
#define M68KCPU__HEADER
// notaz: something's missing this
#include <stdint.h>
typedef uint64_t UINT64;
typedef uint32_t UINT32;
typedef uint16_t UINT16;
typedef uint8_t UINT8;
#ifndef UINT64
#define UINT64 unsigned long long
#endif
#ifndef UINT16
#define UINT32 unsigned int
#define UINT16 unsigned short
#define UINT8 unsigned char
#endif
#include "m68k.h"
#include <limits.h>
@ -71,12 +74,8 @@ typedef uint8_t UINT8;
#define uint32 unsigned int /* AWJ: changed from long to int */
/* signed and unsigned int must be at least 32 bits wide */
//#define sint signed int
//#define uint unsigned int
#define sint _sint
#define uint _uint
typedef signed int sint;
typedef unsigned int uint;
#define sint signed int
#define uint unsigned int
#if M68K_USE_64_BIT
@ -143,7 +142,6 @@ typedef unsigned int uint;
/* Exception Vectors handled by emulation */
#define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */
#define EXCEPTION_ADDRESS_ERROR 3 /* This one is partially emulated (doesn't stack a proper frame yet) */
#undef EXCEPTION_ILLEGAL_INSTRUCTION
#define EXCEPTION_ILLEGAL_INSTRUCTION 4
#define EXCEPTION_ZERO_DIVIDE 5
#define EXCEPTION_CHK 6
@ -920,15 +918,12 @@ typedef struct
void (*instr_hook_callback)(void); /* Called every instruction cycle prior to execution */
// notaz
sint cyc_initial_cycles;
sint cyc_remaining_cycles;
sint not_polling;
} m68ki_cpu_core;
// notaz
extern m68ki_cpu_core *m68ki_cpu_p;
#define m68ki_cpu (*m68ki_cpu_p)
#define m68ki_initial_cycles m68ki_cpu_p->cyc_initial_cycles
#define m68ki_remaining_cycles m68ki_cpu_p->cyc_remaining_cycles
@ -1541,7 +1536,7 @@ INLINE void m68ki_set_sr_noint_nosp(uint value)
INLINE void m68ki_set_sr(uint value)
{
m68ki_set_sr_noint(value);
if (GET_CYCLES() > 0) // notaz
if (GET_CYCLES() >= 0) // notaz
m68ki_check_interrupts();
}
@ -1627,7 +1622,7 @@ INLINE void m68ki_stack_frame_buserr(uint sr)
/* Format 8 stack frame (68010).
* 68010 only. This is the 29 word bus/address error frame.
*/
INLINE void m68ki_stack_frame_1000(uint pc, uint sr, uint vector)
void m68ki_stack_frame_1000(uint pc, uint sr, uint vector)
{
/* VERSION
* NUMBER
@ -1681,7 +1676,7 @@ INLINE void m68ki_stack_frame_1000(uint pc, uint sr, uint vector)
* if the error happens at an instruction boundary.
* PC stacked is address of next instruction.
*/
INLINE void m68ki_stack_frame_1010(uint sr, uint vector, uint pc)
void m68ki_stack_frame_1010(uint sr, uint vector, uint pc)
{
/* INTERNAL REGISTER */
m68ki_push_16(0);
@ -1728,7 +1723,7 @@ INLINE void m68ki_stack_frame_1010(uint sr, uint vector, uint pc)
* if the error happens during instruction execution.
* PC stacked is address of instruction in progress.
*/
INLINE void m68ki_stack_frame_1011(uint sr, uint vector, uint pc)
void m68ki_stack_frame_1011(uint sr, uint vector, uint pc)
{
/* INTERNAL REGISTERS (18 words) */
m68ki_push_32(0);
@ -1972,7 +1967,7 @@ m68k_read_memory_8(0x00ffff01);
/* Service an interrupt request and start exception processing */
INLINE void m68ki_exception_interrupt(uint int_level)
void m68ki_exception_interrupt(uint int_level)
{
uint vector;
uint sr;

View file

@ -122,9 +122,6 @@ static const char* g_version = "3.31";
#endif /* DECL_SPEC */
#ifdef USE_LIBRETRO_VFS
#include "file_stream_transforms.h"
#endif
/* ======================================================================== */
/* ============================== PROTOTYPES ============================== */
@ -641,9 +638,6 @@ int get_oper_cycles(opcode_struct* op, int ea_mode, int cpu_type)
strcmp(op->name, "suba") == 0))
return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2;
if(cpu_type == CPU_TYPE_000 && ea_mode == EA_MODE_I && op->size == 8 && strcmp(op->name, "btst") == 0)
return op->cycles[cpu_type] + g_ea_cycle_table[ea_mode][cpu_type][size] + 2;
if(strcmp(op->name, "jmp") == 0)
return op->cycles[cpu_type] + g_jmp_cycle_table[ea_mode];
if(strcmp(op->name, "jsr") == 0)
@ -1049,11 +1043,6 @@ void process_opcode_handlers(FILE* filep)
if(opinfo == NULL)
error_exit("Unable to find matching table entry for %s", func_name);
#if 1 /* PD hack: 000 only */
if (opinfo->cpus[0] == UNSPECIFIED_CH)
continue;
#endif
replace->length = 0;
/* Generate opcode variants */

File diff suppressed because it is too large Load diff

View file

@ -1,87 +1,26 @@
int sh2_drc_init(SH2 *sh2);
void sh2_drc_finish(SH2 *sh2);
void sh2_drc_wcheck_ram(u32 a, unsigned len, SH2 *sh2);
void sh2_drc_wcheck_da(u32 a, unsigned len, SH2 *sh2);
void sh2_drc_wcheck_ram(unsigned int a, int val, int cpuid);
void sh2_drc_wcheck_da(unsigned int a, int val, int cpuid);
#ifdef DRC_SH2
void sh2_drc_mem_setup(SH2 *sh2);
void sh2_drc_flush_all(void);
void sh2_drc_frame(void);
#else
#define sh2_drc_mem_setup(x)
#define sh2_drc_flush_all()
#define sh2_drc_frame()
#endif
#define BLOCK_INSN_LIMIT 1024
#define BLOCK_INSN_LIMIT 128
/* op_flags */
#define OF_DELAY_OP (1 << 0)
#define OF_BTARGET (1 << 1)
#define OF_LOOP (3 << 2) // NONE, IDLE, DELAY, POLL loop
#define OF_B_IN_DS (1 << 4)
#define OF_DELAY_INSN (1 << 5) // DT, (TODO ADD+CMP?)
#define OF_POLL_INSN (1 << 6) // MOV @(...),Rn (no post increment), TST @(...)
#define OF_BASIC_LOOP (1 << 7) // pinnable loop without any branches in it
#define OF_T_SET (1 << 2) // T is known to be set
#define OF_T_CLEAR (1 << 3) // ... clear
#define OF_IDLE_LOOP (1 << 2)
#define OF_DELAY_LOOP (2 << 2)
#define OF_POLL_LOOP (3 << 2)
u16 scan_block(u32 base_pc, int is_slave, u8 *op_flags, u32 *end_pc,
u32 *base_literals, u32 *end_literals);
#if defined(DRC_SH2) && defined(__GNUC__) && !defined(__clang__)
// direct access to some host CPU registers used by the DRC if gcc is used.
// XXX MUST match SHR_SR definitions in cpu/drc/emit_*.c; should be moved there
// XXX yuck, there's no portable way to determine register size. Use long long
// if target is 64 bit and data model is ILP32 or LLP64(windows), else long
#if defined(__arm__)
#define DRC_SR_REG "r10"
#define DRC_REG_LL 0 // 32 bit
#elif defined(__aarch64__)
#define DRC_SR_REG "r28"
#define DRC_REG_LL (__ILP32__ || _WIN32)
#elif defined(__mips__)
#define DRC_SR_REG "s6"
#define DRC_REG_LL (_MIPS_SZPTR > _MIPS_SZLONG) // (_MIPS_SIM == _ABIN32)
#elif defined(__riscv__) || defined(__riscv)
#define DRC_SR_REG "s11"
#define DRC_REG_LL 0 // no ABI for (__ILP32__ && __riscv_xlen != 32)
#elif defined(__powerpc__) || defined(__ppc__) || defined(__PPC__)
#define DRC_SR_REG "r28"
#define DRC_REG_LL 0 // no ABI for __ILP32__
//i386 only has 8 registers and reserving one of them causes too much spilling
//#elif defined(__i386__)
//#define DRC_SR_REG "edi"
//#define DRC_REG_LL 0 // 32 bit
#elif defined(__x86_64__)
#define DRC_SR_REG "rbx"
#define DRC_REG_LL (__ILP32__ || _WIN32)
#endif
#endif
#ifdef DRC_SR_REG
// XXX this is more clear but produces too much overhead for slow platforms
extern void REGPARM(1) (*sh2_drc_save_sr)(SH2 *sh2);
extern void REGPARM(1) (*sh2_drc_restore_sr)(SH2 *sh2);
// NB: sh2_sr MUST have register size if optimizing with -O3 (-fif-conversion)
#if DRC_REG_LL
#define DRC_DECLARE_SR register long long _sh2_sr asm(DRC_SR_REG)
#else
#define DRC_DECLARE_SR register long _sh2_sr asm(DRC_SR_REG)
#endif
// NB: save/load SR register only when DRC is executing and not in DMA access
#define DRC_SAVE_SR(sh2) \
if (likely((sh2->state & (SH2_IN_DRC|SH2_STATE_SLEEP)) == SH2_IN_DRC)) \
sh2->sr = (s32)_sh2_sr
// host_call(sh2_drc_save_sr, (SH2 *))(sh2)
#define DRC_RESTORE_SR(sh2) \
if (likely((sh2->state & (SH2_IN_DRC|SH2_STATE_SLEEP)) == SH2_IN_DRC)) \
_sh2_sr = (s32)sh2->sr
// host_call(sh2_drc_restore_sr, (SH2 *))(sh2)
#else
#define DRC_DECLARE_SR
#define DRC_SAVE_SR(sh2)
#define DRC_RESTORE_SR(sh2)
#endif
void scan_block(unsigned int base_pc, int is_slave,
unsigned char *op_flags, unsigned int *end_pc,
unsigned int *end_literals);

View file

@ -108,7 +108,6 @@
//#include "debugger.h"
//#include "sh2.h"
//#include "sh2comn.h"
#undef INLINE
#define INLINE static
//CPU_DISASSEMBLE( sh2 );
@ -372,7 +371,7 @@ INLINE void BRA(sh2_state *sh2, UINT32 d)
#if BUSY_LOOP_HACKS
if (disp == -2)
{
UINT32 next_opcode = (UINT32)(UINT16)RW( sh2, sh2->ppc & AM );
UINT32 next_opcode = RW( sh2, sh2->ppc & AM );
/* BRA $
* NOP
*/
@ -800,10 +799,9 @@ INLINE void DT(sh2_state *sh2, UINT32 n)
sh2->sr |= T;
else
sh2->sr &= ~T;
sh2->no_polling = SH2_NO_POLLING;
#if BUSY_LOOP_HACKS
{
UINT32 next_opcode = (UINT32)(UINT16)RW( sh2, sh2->ppc & AM );
UINT32 next_opcode = RW( sh2, sh2->ppc & AM );
/* DT Rn
* BF $-2
*/
@ -1050,12 +1048,12 @@ INLINE void MAC_W(sh2_state *sh2, UINT32 m, UINT32 n)
INT32 tempm, tempn, dest, src, ans;
UINT32 templ;
tempn = (INT32)(INT16) RW( sh2, sh2->r[n] );
tempn = (INT32) RW( sh2, sh2->r[n] );
sh2->r[n] += 2;
tempm = (INT32)(INT16) RW( sh2, sh2->r[m] );
tempm = (INT32) RW( sh2, sh2->r[m] );
sh2->r[m] += 2;
templ = sh2->macl;
tempm = (tempn * tempm);
tempm = ((INT32) (short) tempn * (INT32) (short) tempm);
if ((INT32) sh2->macl >= 0)
dest = 0;
else

View file

@ -465,7 +465,7 @@ static UINT32 op1000(char *buffer, UINT32 pc, UINT16 opcode)
sprintf(buffer, "MOV.B @($%02X,%s),R0", (opcode & 15), regname[Rm]);
break;
case 5:
sprintf(buffer, "MOV.W @($%02X,%s),R0", (opcode & 15) * 2, regname[Rm]);
sprintf(buffer, "MOV.W @($%02X,%s),R0", (opcode & 15), regname[Rm]);
break;
case 8:
sprintf(buffer, "CMP/EQ #$%02X,R0", (opcode & 0xff));
@ -610,7 +610,6 @@ unsigned DasmSH2(char *buffer, unsigned pc, UINT16 opcode)
case 14: flags = op1110(buffer,pc,opcode); break;
default: flags = op1111(buffer,pc,opcode); break;
}
(void)flags;
return 0;//2 | flags | DASMFLAG_SUPPORTED;
}

View file

@ -1,7 +1,7 @@
#include "../sh2.h"
#ifdef DRC_CMP
#include "../compiler.h"
#include "../compiler.c"
#define BUSY_LOOP_HACKS 0
#else
#define BUSY_LOOP_HACKS 1
@ -9,36 +9,34 @@
// MAME types
#ifndef INT8
typedef s8 INT8;
typedef s16 INT16;
typedef s32 INT32;
typedef u32 UINT32;
typedef u16 UINT16;
typedef u8 UINT8;
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) \
static inline unsigned int name(SH2 *sh2, unsigned int a) \
{ \
unsigned int ret; \
sh2->sr |= (sh2->icount << 12) | (sh2->no_polling); \
sh2->sr |= sh2->icount << 12; \
ret = cname(a, sh2); \
sh2->icount = (signed int)sh2->sr >> 12; \
sh2->no_polling = (sh2->sr & SH2_NO_POLLING); \
sh2->sr &= 0x3f3; \
return ret; \
}
#define MAKE_WRITEFUNC(name, cname) \
static __inline void name(SH2 *sh2, unsigned int a, unsigned int d) \
static inline void name(SH2 *sh2, unsigned int a, unsigned int d) \
{ \
sh2->sr |= (sh2->icount << 12) | (sh2->no_polling); \
sh2->sr |= sh2->icount << 12; \
cname(a, d, sh2); \
sh2->icount = (signed int)sh2->sr >> 12; \
sh2->no_polling = (sh2->sr & SH2_NO_POLLING); \
sh2->sr &= 0x3f3; \
}
@ -123,25 +121,13 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles)
if (sh2->delay)
{
sh2->ppc = sh2->delay;
opcode = (UINT32)(UINT16)RW(sh2, sh2->delay);
// TODO: more branch types
if ((opcode >> 13) == 5) { // BRA/BSR
sh2->r[15] -= 4;
WL(sh2, sh2->r[15], sh2->sr);
sh2->r[15] -= 4;
WL(sh2, sh2->r[15], sh2->pc);
sh2->pc = RL(sh2, sh2->vbr + 6 * 4);
sh2->icount -= 5;
opcode = 9; // NOP
}
opcode = RW(sh2, sh2->delay);
sh2->pc -= 2;
}
else
{
sh2->ppc = sh2->pc;
opcode = (UINT32)(UINT16)RW(sh2, sh2->pc);
opcode = RW(sh2, sh2->pc);
}
sh2->delay = 0;
@ -169,16 +155,14 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles)
sh2->icount--;
if (sh2->test_irq && !sh2->delay)
if (sh2->test_irq && !sh2->delay && sh2->pending_level > ((sh2->sr >> 4) & 0x0f))
{
int level = sh2->pending_level;
if (level > ((sh2->sr >> 4) & 0x0f))
{
int vector = sh2->irq_callback(sh2, level);
sh2_do_irq(sh2, level, vector);
}
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 */
@ -218,14 +202,14 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles)
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, NULL);
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)
if (sh2->icount < 0)
break;
}
@ -236,13 +220,13 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles)
if (sh2->delay)
{
sh2->ppc = sh2->delay;
opcode = (UINT32)(UINT16)RW(sh2, sh2->delay);
opcode = RW(sh2, sh2->delay);
sh2->pc -= 2;
}
else
{
sh2->ppc = sh2->pc;
opcode = (UINT32)(UINT16)RW(sh2, sh2->pc);
opcode = RW(sh2, sh2->pc);
}
sh2->delay = 0;

View file

@ -84,7 +84,7 @@ int sh2_irl_irq(SH2 *sh2, int level, int nested_call)
// 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);
sh2->m68krcycles_done += C_SH2_TO_M68K(*sh2, 13);
}
else
sh2->test_irq = 1;
@ -115,7 +115,6 @@ void sh2_pack(const SH2 *sh2, unsigned char *buff)
p[0] = sh2->pending_int_irq;
p[1] = sh2->pending_int_vector;
p[2] = sh2->m68krcycles_done;
}
void sh2_unpack(SH2 *sh2, const unsigned char *buff)
@ -128,7 +127,6 @@ void sh2_unpack(SH2 *sh2, const unsigned char *buff)
sh2->pending_int_irq = p[0];
sh2->pending_int_vector = p[1];
sh2->test_irq = 1;
sh2->m68krcycles_done = p[2];
}
#ifdef DRC_CMP
@ -239,7 +237,7 @@ static void dump_regs(SH2 *sh2)
printf("%csh2 SR: %03x PR: %08x\n", csh2, sh2->sr, sh2->pr);
}
void REGPARM(1) do_sh2_cmp(SH2 *current)
void do_sh2_cmp(SH2 *current)
{
static int current_slave;
static u32 current_val;
@ -253,13 +251,6 @@ void REGPARM(1) do_sh2_cmp(SH2 *current)
int cycles;
int i, ret;
#if 0
sr = current->sr;
current->sr &= 0x3f3;
do_sh2_trace(current, (signed int)sr >> 12);
current->sr = sr;
return;
#endif
sh2ref[1].is_slave = 1;
while (1) {

View file

@ -1,69 +1,52 @@
#ifndef __SH2_H__
#define __SH2_H__
#include <pico/pico_types.h>
#include <pico/pico_port.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_REGS, // register set size
SHR_T = 29, SHR_MEM = 30, SHR_TMP = 31, // drc specific pseudo regs
} sh2_reg_e;
#define SHR_R(n) (SHR_R0+(n))
typedef struct SH2_
{
// registers. this MUST correlate with enum sh2_reg_e.
uint32_t r[16] ALIGNED(32);
uint32_t pc; // 40
uint32_t ppc;
uint32_t pr;
uint32_t sr;
uint32_t gbr, vbr; // 50
uint32_t mach, macl; // 58
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;
const void *read8_map; // 60
const void *read16_map;
const void *read32_map;
const void **write8_tab;
const void **write16_tab;
const void **write32_tab;
// drc stuff
int drc_tmp;
int drc_tmp; // 70
int irq_cycles;
void *p_bios; // convenience pointers
void *p_da;
void *p_sdram;
void *p_sdram; // 80
void *p_rom;
void *p_dram;
void *p_drcblk_da;
void *p_drcblk_ram;
unsigned int pdb_io_csum[2];
#define SH2_STATE_RUN (1 << 0) // to prevent recursion
#define SH2_STATE_SLEEP (1 << 1) // temporarily stopped (DMA, IO, ...)
#define SH2_STATE_SLEEP (1 << 1)
#define SH2_STATE_CPOLL (1 << 2) // polling comm regs
#define SH2_STATE_VPOLL (1 << 3) // polling VDP
#define SH2_STATE_RPOLL (1 << 4) // polling address in SDRAM
#define SH2_TIMER_RUN (1 << 6) // SOC WDT timer is running
#define SH2_IN_DRC (1 << 7) // DRC in use
unsigned int state;
uint32_t poll_addr;
unsigned int poll_cycles;
unsigned int poll_addr;
int poll_cycles;
int poll_cnt;
// NB MUST be a bit unused in SH2 SR, see also cpu/sh2/compiler.c!
#define SH2_NO_POLLING (1 << 10) // poll detection control
int no_polling;
// DRC branch cache. size must be 2^n and <=128
int rts_cache_idx;
struct { uint32_t pc; void *code; } rts_cache[16];
struct { uint32_t pc; void *code; } branch_cache[128];
// interpreter stuff
int icount; // cycles left in current timeslice
@ -81,22 +64,21 @@ typedef struct SH2_
unsigned int cycles_timeslice;
struct SH2_ *other_sh2;
int (*run)(struct SH2_ *, int);
// we use 68k reference cycles for easier sync
unsigned int m68krcycles_done;
unsigned int mult_m68k_to_sh2;
unsigned int mult_sh2_to_m68k;
uint8_t data_array[0x1000]; // cache (can be used as RAM)
uint32_t peri_regs[0x200/4]; // peripheral regs
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)(((uint64_t)(c) * (xsh2)->mult_m68k_to_sh2) >> CYCLE_MULT_SHIFT)
((int)((c) * (xsh2).mult_m68k_to_sh2) >> CYCLE_MULT_SHIFT)
#define C_SH2_TO_M68K(xsh2, c) \
(int)(((uint64_t)(c+3U) * (xsh2)->mult_sh2_to_m68k) >> CYCLE_MULT_SHIFT)
((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);
@ -110,21 +92,17 @@ 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 void sh2_execute_prepare(SH2 *sh2, int use_drc)
{
#ifdef DRC_SH2
sh2->run = use_drc ? sh2_execute_drc : sh2_execute_interpreter;
#else
sh2->run = sh2_execute_interpreter;
#endif
}
static __inline int sh2_execute(SH2 *sh2, int cycles)
static inline int sh2_execute(SH2 *sh2, int cycles, int use_drc)
{
int ret;
sh2->cycles_timeslice = cycles;
ret = sh2->run(sh2, 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;
}
@ -134,17 +112,17 @@ static __inline int sh2_execute(SH2 *sh2, int cycles)
// pico memhandlers
// XXX: move somewhere else
u32 REGPARM(2) p32x_sh2_read8(u32 a, SH2 *sh2);
u32 REGPARM(2) p32x_sh2_read16(u32 a, SH2 *sh2);
u32 REGPARM(2) p32x_sh2_read32(u32 a, SH2 *sh2);
void REGPARM(3) p32x_sh2_write8 (u32 a, u32 d, SH2 *sh2);
void REGPARM(3) p32x_sh2_write16(u32 a, u32 d, SH2 *sh2);
void REGPARM(3) p32x_sh2_write32(u32 a, u32 d, SH2 *sh2);
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 REGPARM(1) do_sh2_cmp(SH2 *current);
void do_sh2_cmp(SH2 *current);
#endif
#endif /* __SH2_H__ */

View file

@ -1,132 +1,80 @@
LOCAL_PATH := $(call my-dir)
CORE_DIR := $(LOCAL_PATH)/..
COMMON_DIR := $(CORE_DIR)/platform/common
LIBRETRO_DIR := $(CORE_DIR)/platform/libretro
LIBRETRO_COMM_DIR := $(LIBRETRO_DIR)/libretro-common
UNZIP_DIR := $(CORE_DIR)/unzip
R := $(CORE_DIR)/
FR := $(R)
include $(CLEAR_VARS)
SRCS_COMMON :=
DEFINES :=
ARCH := $(TARGET_ARCH)
ifeq ($(NEON_BUILD)$(TARGET_ARCH_ABI),1armeabi-v7a)
LOCAL_MODULE := retro_picodrive-neon
else
LOCAL_MODULE := retro_picodrive
endif
use_cyclone := 0
use_fame := 1
use_musashi := 0
use_drz80 := 0
use_cz80 := 1
use_sh2drc := 0
use_svpdrc := 0
R := ../
FR := $(LOCAL_PATH)/$(R)
asm_memory := 0
asm_render := 0
asm_ym2612 := 0
asm_misc := 0
asm_cdmemory := 0
asm_mix := 0
asm_32xdraw := 0
asm_32xmemory := 0
use_cyclone = 0
use_fame = 0
use_musashi = 0
use_drz80 = 0
use_cz80 = 0
use_sh2drc = 0
use_sh2mame = 0
use_svpdrc = 0
asm_memory = 0
asm_render = 0
asm_ym2612 = 0
asm_misc = 0
asm_cdpico = 0
asm_cdmemory = 0
asm_mix = 0
ifeq ($(TARGET_ARCH),arm)
# use_cyclone := 1
# use_fame := 0
# use_drz80 := 1
# use_cz80 := 0
use_sh2drc := 1
# use_svpdrc := 1
LOCAL_ARM_MODE := arm
ifeq ($(NEON_BUILD),1)
LOCAL_ARM_NEON := true
endif
# asm_memory := 1
# asm_render := 1
# asm_ym2612 := 1
# asm_misc := 1
# asm_cdmemory := 1
# asm_mix := 1
# asm_32xdraw := 1
# asm_32xmemory := 1
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
use_fame = 1
use_cz80 = 1
use_sh2mame = 1
endif
ifeq ($(TARGET_ARCH_ABI),armeabi)
CYCLONE_CONFIG := cyclone_config_armv4.h
endif
# sources
SRCS_COMMON :=
DEFINES :=
ARCH := $(TARGET_ARCH)
include $(R)platform/common/common.mak
include $(COMMON_DIR)/common.mak
LOCAL_SRC_FILES += $(SRCS_COMMON)
LOCAL_SRC_FILES += $(R)platform/libretro.c
LOCAL_SRC_FILES += $(R)platform/common/mp3.c
LOCAL_SRC_FILES += $(R)platform/common/mp3_dummy.c
LCHDR = $(CORE_DIR)/pico/cd/libchdr
LCHDR_LZMA = $(LCHDR)/deps/lzma-24.05
LCHDR_ZSTD = $(LCHDR)/deps/zstd-1.5.6/lib
# zlib/unzip
LOCAL_SRC_FILES += $(R)zlib/gzio.c $(R)zlib/inffast.c $(R)zlib/inflate.c \
$(R)zlib/inftrees.c $(R)zlib/trees.c $(R)zlib/deflate.c \
$(R)zlib/crc32.c $(R)zlib/adler32.c $(R)zlib/zutil.c \
$(R)zlib/compress.c $(R)zlib/uncompr.c
SOURCES_C := $(LIBRETRO_DIR)/libretro.c \
$(LIBRETRO_COMM_DIR)/formats/png/rpng.c \
$(LIBRETRO_COMM_DIR)/streams/trans_stream.c \
$(LIBRETRO_COMM_DIR)/streams/trans_stream_pipe.c \
$(LIBRETRO_COMM_DIR)/streams/trans_stream_zlib.c \
$(LIBRETRO_COMM_DIR)/file/file_path_io.c \
$(LIBRETRO_COMM_DIR)/file/file_path.c \
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.c \
$(LIBRETRO_COMM_DIR)/time/rtime.c \
$(LIBRETRO_COMM_DIR)/string/stdstring.c \
$(LIBRETRO_COMM_DIR)/encodings/encoding_utf.c \
$(LIBRETRO_COMM_DIR)/compat/compat_strcasestr.c \
$(LIBRETRO_COMM_DIR)/compat/compat_strl.c \
$(COMMON_DIR)/mp3.c \
$(COMMON_DIR)/mp3_sync.c \
$(COMMON_DIR)/mp3_dummy.c \
$(UNZIP_DIR)/unzip.c \
$(LCHDR)/src/libchdr_bitstream.c \
$(LCHDR)/src/libchdr_cdrom.c \
$(LCHDR)/src/libchdr_chd.c \
$(LCHDR)/src/libchdr_flac.c \
$(LCHDR)/src/libchdr_huffman.c \
$(LCHDR_LZMA)/src/Alloc.c \
$(LCHDR_LZMA)/src/CpuArch.c \
$(LCHDR_LZMA)/src/Delta.c \
$(LCHDR_LZMA)/src/LzFind.c \
$(LCHDR_LZMA)/src/LzmaDec.c \
$(LCHDR_LZMA)/src/LzmaEnc.c \
$(LCHDR_LZMA)/src/Sort.c \
$(LCHDR_ZSTD)/common/entropy_common.c \
$(LCHDR_ZSTD)/common/error_private.c \
$(LCHDR_ZSTD)/common/fse_decompress.c \
$(LCHDR_ZSTD)/common/xxhash.c \
$(LCHDR_ZSTD)/common/zstd_common.c \
$(LCHDR_ZSTD)/decompress/huf_decompress.c \
$(LCHDR_ZSTD)/decompress/zstd_ddict.c \
$(LCHDR_ZSTD)/decompress/zstd_decompress_block.c \
$(LCHDR_ZSTD)/decompress/zstd_decompress.c
LOCAL_SRC_FILES += $(R)unzip/unzip.c $(R)unzip/unzip_stream.c
COREFLAGS := $(addprefix -D,$(DEFINES)) -fno-strict-aliasing -DUSE_LIBCHDR=1 -DZ7_ST -DZSTD_DISABLE_ASM
COREFLAGS += -I$(LCHDR)/include -I$(LCHDR_LZMA)/include -I$(LCHDR_ZSTD)
ifeq (,$(call gte,$(APP_PLATFORM_LEVEL),18))
ifneq ($(TARGET_ARCH_ABI),arm64-v8a)
# HACK
COREFLAGS += -Dgetauxval=0*
endif
endif
LOCAL_C_INCLUDES += $(R)
GIT_REVISION := $(shell git rev-parse --short HEAD || echo unknown)
COREFLAGS += -DREVISION=\"$(GIT_REVISION)\"
ifneq ($(filter armeabi%, $(TARGET_ARCH_ABI)),)
$(CORE_DIR)/pico/pico_int_offs.h:
cp $(CORE_DIR)/tools/offsets/generic-ilp32-offsets.h $@
.PHONY: $(CORE_DIR)/pico/pico_int_offs.h
$(filter %.S,$(SRCS_COMMON)): $(CORE_DIR)/pico/pico_int_offs.h
endif
include $(CLEAR_VARS)
LOCAL_MODULE := retro
LOCAL_SRC_FILES := $(SRCS_COMMON) $(SOURCES_C)
LOCAL_CFLAGS := $(COREFLAGS)
LOCAL_C_INCLUDES := $(CORE_DIR) $(LIBRETRO_COMM_DIR)/include
LOCAL_LDFLAGS := -Wl,-version-script=$(LIBRETRO_DIR)/link.T
LOCAL_LDLIBS := -llog -lz
LOCAL_ARM_MODE := arm
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_ARM_NEON := true
endif
LOCAL_CFLAGS += $(addprefix -D,$(DEFINES))
LOCAL_CFLAGS += -Wall -O3 -ffast-math -DNDEBUG
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)

View file

@ -1,19 +1,18 @@
/*
* PicoDrive
* (C) notaz, 2009,2010,2013
* (C) irixxxx, 2019-2024
*
* 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"
#include <cpu/sh2/compiler.h>
#include "../../cpu/sh2/compiler.h"
struct Pico32x Pico32x;
SH2 sh2s[2];
#define SH2_IDLE_STATES (SH2_STATE_CPOLL|SH2_STATE_VPOLL|SH2_STATE_RPOLL|SH2_STATE_SLEEP)
#define SH2_IDLE_STATES (SH2_STATE_CPOLL|SH2_STATE_VPOLL|SH2_STATE_SLEEP)
static int REGPARM(2) sh2_irq_cb(SH2 *sh2, int level)
{
@ -31,43 +30,38 @@ static int REGPARM(2) sh2_irq_cb(SH2 *sh2, int level)
}
// MUST specify active_sh2 when called from sh2 memhandlers
void p32x_update_irls(SH2 *active_sh2, unsigned int m68k_cycles)
void p32x_update_irls(SH2 *active_sh2, int m68k_cycles)
{
int irqs, mlvl = 0, slvl = 0;
int mrun, srun;
if ((Pico32x.regs[0] & (P32XS_nRES|P32XS_ADEN)) != (P32XS_nRES|P32XS_ADEN))
return;
if (active_sh2 != NULL)
m68k_cycles = sh2_cycles_done_m68k(active_sh2);
// find top bit = highest irq number (0 <= irl <= 14/2) by binary search
// msh2
irqs = Pico32x.sh2irqi[0];
if (irqs >= 0x10) mlvl += 8, irqs >>= 4;
if (irqs >= 0x04) mlvl += 4, irqs >>= 2;
if (irqs >= 0x02) mlvl += 2, irqs >>= 1;
irqs = Pico32x.sh2irqs | Pico32x.sh2irqi[0];
while ((irqs >>= 1))
mlvl++;
mlvl *= 2;
// ssh2
irqs = Pico32x.sh2irqi[1];
if (irqs >= 0x10) slvl += 8, irqs >>= 4;
if (irqs >= 0x04) slvl += 4, irqs >>= 2;
if (irqs >= 0x02) slvl += 2, irqs >>= 1;
irqs = Pico32x.sh2irqs | Pico32x.sh2irqi[1];
while ((irqs >>= 1))
slvl++;
slvl *= 2;
mrun = sh2_irl_irq(&msh2, mlvl, msh2.state & SH2_STATE_RUN);
mrun = sh2_irl_irq(&msh2, mlvl, active_sh2 == &msh2);
if (mrun) {
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_IDLE_STATES & ~SH2_STATE_SLEEP, m68k_cycles);
if (msh2.state & SH2_STATE_RUN)
sh2_end_run(&msh2, 0);
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, ssh2.state & SH2_STATE_RUN);
srun = sh2_irl_irq(&ssh2, slvl, active_sh2 == &ssh2);
if (srun) {
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_IDLE_STATES & ~SH2_STATE_SLEEP, m68k_cycles);
if (ssh2.state & SH2_STATE_RUN)
sh2_end_run(&ssh2, 0);
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);
@ -76,17 +70,16 @@ void p32x_update_irls(SH2 *active_sh2, unsigned int m68k_cycles)
// 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, unsigned int m68k_cycles, unsigned int mask)
void p32x_trigger_irq(SH2 *sh2, int m68k_cycles, unsigned int mask)
{
Pico32x.sh2irqi[0] |= mask & P32XI_VRES;
Pico32x.sh2irqi[1] |= mask & P32XI_VRES;
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, unsigned int 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;
@ -105,54 +98,26 @@ void Pico32xStartup(void)
{
elprintf(EL_STATUS|EL_32X, "32X startup");
PicoIn.AHW |= PAHW_32X;
// TODO: OOM handling
if (Pico32xMem == NULL) {
Pico32xMem = plat_mmap(0x06000000, sizeof(*Pico32xMem), 0, 0);
if (Pico32xMem == NULL) {
elprintf(EL_STATUS, "OOM");
return;
}
memset(Pico32xMem, 0, sizeof(struct Pico32xMem));
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;
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;
else
Pico32x.vdp_regs[0] &= ~P32XV_nPAL;
rendstatus_old = -1;
Pico32xPrepare();
emu_32x_startup();
}
void Pico32xShutdown(void)
{
Pico32x.sh2_regs[0] &= ~P32XS2_ADEN;
rendstatus_old = -1;
PicoIn.AHW &= ~PAHW_32X;
if (PicoIn.AHW & PAHW_MCD)
PicoMemSetupCD();
else
PicoMemSetup();
emu_32x_startup();
}
#define HWSWAP(x) (((x) << 16) | ((x) >> 16))
void p32x_reset_sh2s(void)
{
elprintf(EL_32X, "sh2 reset");
@ -165,30 +130,28 @@ void p32x_reset_sh2s(void)
// if we don't have BIOS set, perform it's work here.
// MSH2
if (p32x_bios_m == NULL) {
sh2_set_gbr(0, 0x20004000);
unsigned int idl_src, idl_dst, idl_size; // initial data load
unsigned int vbr;
if (!Pico.m.ncart_in) { // copy IDL from cartridge
unsigned int idl_src, idl_dst, idl_size; // initial data load
unsigned int vbr;
// initial data
idl_src = CPU_BE2(*(u32 *)(Pico.rom + 0x3d4)) & ~0xf0000000;
idl_dst = CPU_BE2(*(u32 *)(Pico.rom + 0x3d8)) & ~0xf0000000;
idl_size= CPU_BE2(*(u32 *)(Pico.rom + 0x3dc));
// copy in guest memory space
idl_src += 0x2000000;
idl_dst += 0x6000000;
while (idl_size >= 4) {
p32x_sh2_write32(idl_dst, p32x_sh2_read32(idl_src, &msh2), &msh2);
idl_src += 4, idl_dst += 4, idl_size -= 4;
}
// VBR
vbr = CPU_BE2(*(u32 *)(Pico.rom + 0x3e8));
sh2_set_vbr(0, vbr);
// checksum and M_OK
Pico32x.regs[0x28 / 2] = *(u16 *)(Pico.rom + 0x18e);
// 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
}
@ -197,7 +160,7 @@ void p32x_reset_sh2s(void)
unsigned int vbr;
// GBR/VBR
vbr = CPU_BE2(*(u32 *)(Pico.rom + 0x3ec));
vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3ec));
sh2_set_gbr(1, 0x20004000);
sh2_set_vbr(1, vbr);
// program will set S_OK
@ -208,6 +171,10 @@ void p32x_reset_sh2s(void)
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)
@ -215,106 +182,90 @@ void PicoPower32x(void)
memset(&Pico32x, 0, sizeof(Pico32x));
Pico32x.regs[0] = P32XS_REN|P32XS_nRES; // verified
Pico32x.regs[0x10/2] = 0xffff;
Pico32x.vdp_regs[0x0a/2] = P32XV_VBLK|P32XV_PEN;
Pico32x.sh2_regs[0] = P32XS2_ADEN;
}
void PicoUnload32x(void)
{
if (PicoIn.AHW & PAHW_32X)
Pico32xShutdown();
sh2_finish(&msh2);
sh2_finish(&ssh2);
if (Pico32xMem != NULL)
plat_munmap(Pico32xMem, sizeof(*Pico32xMem));
Pico32xMem = NULL;
sh2_finish(&msh2);
sh2_finish(&ssh2);
PicoAHW &= ~PAHW_32X;
}
void PicoReset32x(void)
{
if (PicoIn.AHW & PAHW_32X) {
if (PicoAHW & PAHW_32X) {
msh2.m68krcycles_done = ssh2.m68krcycles_done = SekCyclesDone();
p32x_trigger_irq(NULL, SekCyclesDone(), P32XI_VRES);
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_IDLE_STATES, SekCyclesDone());
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_IDLE_STATES, SekCyclesDone());
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_render_frame(void)
static void p32x_start_blank(void)
{
if (Pico32xDrawMode != PDM32X_OFF && !PicoIn.skipFrame) {
if (Pico32xDrawMode != PDM32X_OFF && !PicoSkipFrame) {
int offs, lines;
pprof_start(draw);
offs = 8; lines = 224;
if (Pico.video.reg[1] & 8) {
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.debug_p & PVD_KILL_32X)))
(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_BOTH)
else if (Pico32xDrawMode != PDM32X_32X_ONLY)
PicoDraw32xLayerMdOnly(offs, lines);
pprof_end(draw);
}
}
static void p32x_start_blank(void)
{
// 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;
Pico32xSwapDRAM(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, Pico.t.m68c_aim, P32XI_VINT);
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
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);
}
static void p32x_end_blank(void)
{
// end vblank
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)) {
// NB must precede VInt per hw manual, min 4 SH-2 cycles to pass Mars Check
Pico32x.hint_counter = (int)(-1.5*0x10);
p32x_schedule_hint(NULL, Pico.t.m68c_aim);
}
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
}
void p32x_schedule_hint(SH2 *sh2, unsigned int m68k_cycles)
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
if (!(Pico32x.sh2_regs[0] & 0x80) && (Pico.video.status & PVS_VB2))
// 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;
Pico32x.hint_counter += (Pico32x.sh2_regs[4 / 2] + 1) * (int)(488.5*0x10);
after = Pico32x.hint_counter >> 4;
Pico32x.hint_counter &= 0xf;
after = (Pico32x.sh2_regs[4 / 2] + 1) * 488;
if (sh2 != NULL)
p32x_event_schedule_sh2(sh2, P32X_EVENT_HINT, after);
else
@ -325,8 +276,8 @@ void p32x_schedule_hint(SH2 *sh2, unsigned int m68k_cycles)
static void fillend_event(unsigned int now)
{
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_nFEN;
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, now);
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, now);
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)
@ -341,9 +292,9 @@ typedef void (event_cb)(unsigned int now);
unsigned int p32x_event_times[P32X_EVENT_COUNT];
static unsigned int event_time_next;
static event_cb *p32x_event_cbs[P32X_EVENT_COUNT] = {
p32x_pwm_irq_event, // P32X_EVENT_PWM
fillend_event, // P32X_EVENT_FILLEND
hint_event, // P32X_EVENT_HINT
[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
@ -367,12 +318,8 @@ void p32x_event_schedule_sh2(SH2 *sh2, enum p32x_event event, int after)
p32x_event_schedule(now, event, after);
left_to_next = C_M68K_TO_SH2(sh2, (int)(event_time_next - now));
if (sh2_cycles_left(sh2) > left_to_next) {
if (left_to_next < 1)
left_to_next = 0;
sh2_end_run(sh2, left_to_next);
}
left_to_next = (event_time_next - now) * 3;
sh2_end_run(sh2, left_to_next);
}
static void p32x_run_events(unsigned int until)
@ -414,19 +361,19 @@ static void p32x_run_events(unsigned int until)
oldest, event_time_next);
}
static void run_sh2(SH2 *sh2, unsigned int m68k_cycles)
static inline void run_sh2(SH2 *sh2, int m68k_cycles)
{
unsigned int cycles, done;
int cycles, done;
pevt_log_sh2_o(sh2, EVT_RUN_START);
sh2->state |= SH2_STATE_RUN;
cycles = C_M68K_TO_SH2(sh2, m68k_cycles);
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);
done = sh2_execute(sh2, cycles, PicoOpt & POPT_EN_DRC);
sh2->m68krcycles_done += C_SH2_TO_M68K(sh2, done);
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",
@ -460,30 +407,28 @@ void p32x_sync_other_sh2(SH2 *sh2, unsigned int m68k_target)
// there might be new event to schedule current sh2 to
if (event_time_next) {
left_to_event = C_M68K_TO_SH2(sh2, (int)(event_time_next - m68k_target));
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 = 0;
left_to_event = 1;
sh2_end_run(sh2, left_to_event);
}
}
}
#define STEP_LS 24
#define STEP_N 528 // at least one line (488)
#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, next, timer_cycles;
unsigned int now, target, timer_cycles;
int cycles;
elprintf(EL_32X, "sh2 sync to %u", m68k_target);
if ((Pico32x.regs[0] & (P32XS_nRES|P32XS_ADEN)) != (P32XS_nRES|P32XS_ADEN)) {
if (!(Pico32x.regs[0] & P32XS_nRES)) {
msh2.m68krcycles_done = ssh2.m68krcycles_done = m68k_target;
return; // rare
}
@ -493,7 +438,6 @@ void sync_sh2s_normal(unsigned int m68k_target)
now = ssh2.m68krcycles_done;
timer_cycles = now;
pprof_start(m68k);
while (CYCLES_GT(m68k_target, now))
{
if (event_time_next && CYCLES_GE(now, event_time_next))
@ -502,68 +446,47 @@ void sync_sh2s_normal(unsigned int m68k_target)
target = m68k_target;
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
while (CYCLES_GT(target, now))
{
next = target;
if (CYCLES_GT(target, now + STEP_N))
next = now + STEP_N;
elprintf(EL_32X, "sh2 exec to %u %d,%d/%d, flags %x", next,
next - msh2.m68krcycles_done, next - ssh2.m68krcycles_done,
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);
pprof_start(ssh2);
if (!(ssh2.state & SH2_IDLE_STATES)) {
cycles = next - ssh2.m68krcycles_done;
cycles = target - ssh2.m68krcycles_done;
if (cycles > 0) {
run_sh2(&ssh2, cycles > 20U ? cycles : 20U);
run_sh2(&ssh2, cycles);
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
if (CYCLES_GT(next, target))
next = target;
}
}
pprof_end(ssh2);
pprof_start(msh2);
if (!(msh2.state & SH2_IDLE_STATES)) {
cycles = next - msh2.m68krcycles_done;
cycles = target - msh2.m68krcycles_done;
if (cycles > 0) {
run_sh2(&msh2, cycles > 20U ? cycles : 20U);
run_sh2(&msh2, cycles);
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
if (CYCLES_GT(next, target))
next = target;
}
}
pprof_end(msh2);
now = next;
if (CYCLES_GT(now, msh2.m68krcycles_done)) {
if (!(msh2.state & SH2_IDLE_STATES))
now = target;
if (!(msh2.state & SH2_IDLE_STATES)) {
if (CYCLES_GT(now, msh2.m68krcycles_done))
now = msh2.m68krcycles_done;
}
if (CYCLES_GT(now, ssh2.m68krcycles_done)) {
if (!(ssh2.state & SH2_IDLE_STATES))
if (!(ssh2.state & SH2_IDLE_STATES)) {
if (CYCLES_GT(now, ssh2.m68krcycles_done))
now = ssh2.m68krcycles_done;
}
if (CYCLES_GT(now, timer_cycles+STEP_N)) {
if (msh2.state & SH2_TIMER_RUN)
p32x_timer_do(&msh2, now - timer_cycles);
if (ssh2.state & SH2_TIMER_RUN)
p32x_timer_do(&ssh2, now - timer_cycles);
timer_cycles = now;
}
}
if (msh2.state & SH2_TIMER_RUN)
p32x_timer_do(&msh2, now - timer_cycles);
if (ssh2.state & SH2_TIMER_RUN)
p32x_timer_do(&ssh2, now - timer_cycles);
p32x_timers_do(now - timer_cycles);
timer_cycles = now;
}
pprof_end_sub(m68k);
// advance idle CPUs
if (msh2.state & SH2_IDLE_STATES) {
@ -574,51 +497,52 @@ void sync_sh2s_normal(unsigned int m68k_target)
if (CYCLES_GT(m68k_target, ssh2.m68krcycles_done))
ssh2.m68krcycles_done = m68k_target;
}
// everyone is in sync now
Pico32x.comm_dirty = 0;
}
#define STEP_68K 24
void sync_sh2s_lockstep(unsigned int m68k_target)
{
unsigned int mcycles;
mcycles = msh2.m68krcycles_done;
if (CYCLES_GT(mcycles, ssh2.m68krcycles_done))
if (ssh2.m68krcycles_done < mcycles)
mcycles = ssh2.m68krcycles_done;
while (CYCLES_GT(m68k_target, mcycles)) {
mcycles += STEP_LS;
while (mcycles < m68k_target) {
mcycles += STEP_68K;
sync_sh2s_normal(mcycles);
}
}
#define CPUS_RUN(m68k_cycles) do { \
if (PicoIn.AHW & PAHW_MCD) \
pcd_run_cpus(m68k_cycles); \
else \
SekRunM68k(m68k_cycles); \
\
SekRunM68k(m68k_cycles); \
if ((Pico32x.emu_flags & P32XF_Z80_32X_IO) && Pico.m.z80Run \
&& !Pico.m.z80_reset && (PicoIn.opt & POPT_EN_Z80)) \
&& !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.c"
void PicoFrame32x(void)
{
if (PicoIn.AHW & PAHW_MCD)
pcd_prepare_frame();
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);
PicoFrameStart();
if (Pico32xDrawMode != PDM32X_BOTH)
Pico.est.rendstatus |= PDRAW_SYNC_NEEDED;
PicoFrameHints();
sh2_drc_frame();
elprintf(EL_32X, "poll: %02x %02x %02x",
Pico32x.emu_flags & 3, msh2.state, ssh2.state);
@ -647,24 +571,10 @@ void Pico32xStateLoaded(int is_early)
return;
}
if (CYCLES_GE(sh2s[0].m68krcycles_done - Pico.t.m68c_aim, 500) ||
CYCLES_GE(sh2s[1].m68krcycles_done - Pico.t.m68c_aim, 500))
sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCyclesDone();
sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCyclesDone();
p32x_update_irls(NULL, SekCyclesDone());
p32x_timers_recalc();
p32x_pwm_state_loaded();
p32x_run_events(SekCyclesDone());
}
void Pico32xPrepare(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);
sh2_execute_prepare(&msh2, PicoIn.opt & POPT_EN_DRC);
sh2_execute_prepare(&ssh2, PicoIn.opt & POPT_EN_DRC);
}
// vim:shiftwidth=2:ts=2:expandtab

View file

@ -1,57 +1,33 @@
/*
* PicoDrive
* (C) notaz, 2009,2010
* (C) irixxxx, 2019-2024
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
// NB: 32X officially doesn't support H32 mode. However, it does work since the
// cartridge slot carries the EDCLK signal which is always H40 clock and is used
// as video clock by the 32X. The H32 MD image is overlaid with the 320 px 32X
// image which has the same on-screen width. How the /YS signal on the cartridge
// slot (signalling the display of background color) is processed in this case
// is however unclear and might lead to glitches due to race conditions by the
// different video clocks for H32 and H40.
// BGR555 to native conversion
#if defined(USE_BGR555)
#define PXCONV(t) ((t)&(mr|mg|mb|mp))
#define PXPRIO 0x8000 // prio in MSB
#elif defined(USE_BGR565)
#define PXCONV(t) (((t)&mr) | (((t)&(mg|mb)) << 1) | (((t)&mp) >> 10))
#define PXPRIO 0x0020 // prio in LS green bit
#else // RGB565
#define PXCONV(t) ((((t)&mr) << 11) | (((t)&mg) << 1) | (((t)&(mp|mb)) >> 10))
#define PXPRIO 0x0020 // prio in LS green bit
#endif
int (*PicoScan32xBegin)(unsigned int num);
int (*PicoScan32xEnd)(unsigned int num);
int Pico32xDrawMode;
void *DrawLineDestBase32x;
int DrawLineDestIncrement32x;
static void convert_pal555(int invert_prio)
{
u32 *ps = (void *)Pico32xMem->pal;
u32 *pd = (void *)Pico32xMem->pal_native;
u32 mr = 0x001f001f; // masks for red, green, blue, prio
u32 mg = 0x03e003e0;
u32 mb = 0x7c007c00;
u32 mp = 0x80008000;
u32 inv = 0;
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 = 0x80008000;
inv = 0x00200020;
// place prio to LS green bit
for (i = 0x100/2; i > 0; i--, ps++, pd++) {
u32 t = *ps ^ inv;
*pd = PXCONV(t);
unsigned int t = *ps;
*pd = (((t & m1) << 11) | ((t & m2) << 1) | ((t & m3) >> 10)) ^ inv;
}
Pico32x.dirty_pal = 0;
@ -60,25 +36,19 @@ static void convert_pal555(int invert_prio)
// direct color mode
#define do_line_dc(pd, p32x, pmd, inv, pmd_draw_code) \
{ \
const u16 mr = 0x001f; \
const u16 mg = 0x03e0; \
const u16 mb = 0x7c00; \
const u16 mp = 0x0000; \
unsigned short t; \
int i = 320; \
const unsigned int m1 = 0x001f; \
const unsigned int m2 = 0x03e0; \
const unsigned int m3 = 0x7c00; \
int i; \
\
while (i > 0) { \
for (; i > 0 && (*pmd & 0x3f) == mdbg; pd++, pmd++, i--) { \
t = *p32x++; \
*pd = PXCONV(t); \
} \
for (; i > 0 && (*pmd & 0x3f) != mdbg; pd++, pmd++, i--) { \
t = *p32x++ ^ inv; \
if (t & 0x8000) \
*pd = PXCONV(t); \
else \
pmd_draw_code; \
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); \
} \
}
@ -86,21 +56,15 @@ static void convert_pal555(int invert_prio)
#define do_line_pp(pd, p32x, pmd, pmd_draw_code) \
{ \
unsigned short t; \
int i = 320; \
while (i > 0) { \
for (; i > 0 && (*pmd & 0x3f) == mdbg; pd++, pmd++, i--) { \
t = pal[*(unsigned char *)(MEM_BE2((uintptr_t)(p32x++)))]; \
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; \
} \
for (; i > 0 && (*pmd & 0x3f) != mdbg; pd++, pmd++, i--) { \
t = pal[*(unsigned char *)(MEM_BE2((uintptr_t)(p32x++)))]; \
if (t & PXPRIO) \
*pd = t; \
else \
pmd_draw_code; \
} \
else \
pmd_draw_code; \
} \
}
}
// run length mode
#define do_line_rl(pd, p32x, pmd, pmd_draw_code) \
@ -110,7 +74,7 @@ static void convert_pal555(int invert_prio)
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 & PXPRIO)) \
if ((*pmd & 0x3f) == mdbg || (t & 0x20)) \
*pd = t; \
else \
pmd_draw_code; \
@ -119,18 +83,20 @@ static void convert_pal555(int invert_prio)
}
// this is almost never used (Wiz and menu bg gen only)
void FinalizeLine32xRGB555(int sh, int line, struct PicoEState *est)
void FinalizeLine32xRGB555(int sh, int line)
{
unsigned short *pd = est->DrawLineDest;
unsigned short *pd = DrawLineDest;
unsigned short *pal = Pico32xMem->pal_native;
unsigned char *pmd = est->HighCol + 8;
unsigned char *pmd = HighCol + 8;
unsigned short *dram, *p32x;
unsigned char mdbg;
FinalizeLine555(sh, line, est);
FinalizeLine555(sh, line);
if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 0 || // 32x blanking
(Pico.video.debug_p & PVD_KILL_32X))
// XXX: how is 32col mode hadled by real hardware?
!(Pico.video.reg[12] & 1) || // 32col mode
!(PicoDrawMask & PDRAW_32X_ON))
{
return;
}
@ -164,11 +130,10 @@ void FinalizeLine32xRGB555(int sh, int line, struct PicoEState *est)
#define PICOSCAN_PRE \
PicoScan32xBegin(l + (lines_sft_offs & 0xff)); \
dst = Pico.est.DrawLineDest; \
dst = DrawLineDest; \
#define PICOSCAN_POST \
PicoScan32xEnd(l + (lines_sft_offs & 0xff)); \
Pico.est.DrawLineDest = (char *)Pico.est.DrawLineDest + DrawLineDestIncrement32x; \
#define make_do_loop(name, pre_code, post_code, md_code) \
/* Direct Color Mode */ \
@ -176,9 +141,9 @@ 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 = Pico.est.Draw2FB + \
unsigned char *pmd = PicoDraw2FB + \
328 * (lines_sft_offs & 0xff) + 8; \
unsigned short *palmd = Pico.est.HighPal; \
unsigned short *palmd = HighPal; \
unsigned short *p32x; \
int lines = lines_sft_offs >> 16; \
int l; \
@ -188,7 +153,6 @@ static void do_loop_dc##name(unsigned short *dst, \
p32x = dram + dram[l]; \
do_line_dc(dst, p32x, pmd, inv_bit, md_code); \
post_code; \
dst += DrawLineDestIncrement32x/2 - 320; \
} \
} \
\
@ -197,9 +161,9 @@ 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 = Pico.est.Draw2FB + \
unsigned char *pmd = PicoDraw2FB + \
328 * (lines_sft_offs & 0xff) + 8; \
unsigned short *palmd = Pico.est.HighPal; \
unsigned short *palmd = HighPal; \
unsigned char *p32x; \
int lines = lines_sft_offs >> 16; \
int l; \
@ -210,7 +174,6 @@ static void do_loop_pp##name(unsigned short *dst, \
p32x += (lines_sft_offs >> 8) & 1; \
do_line_pp(dst, p32x, pmd, md_code); \
post_code; \
dst += DrawLineDestIncrement32x/2 - 320; \
} \
} \
\
@ -219,9 +182,9 @@ 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 = Pico.est.Draw2FB + \
unsigned char *pmd = PicoDraw2FB + \
328 * (lines_sft_offs & 0xff) + 8; \
unsigned short *palmd = Pico.est.HighPal; \
unsigned short *palmd = HighPal; \
unsigned short *p32x; \
int lines = lines_sft_offs >> 16; \
int l; \
@ -231,7 +194,6 @@ static void do_loop_rl##name(unsigned short *dst, \
p32x = dram + dram[l]; \
do_line_rl(dst, p32x, pmd, md_code); \
post_code; \
dst += DrawLineDestIncrement32x/2 - 320; \
} \
}
@ -266,12 +228,13 @@ void PicoDraw32xLayer(int offs, int lines, int md_bg)
int lines_sft_offs;
int which_func;
Pico.est.DrawLineDest = (char *)DrawLineDestBase32x + offs * DrawLineDestIncrement32x;
Pico.est.DrawLineDestIncr = DrawLineDestIncrement32x;
DrawLineDest = (char *)DrawLineDestBase + offs * DrawLineDestIncrement;
dram = Pico32xMem->dram[Pico32x.vdp_regs[0x0a/2] & P32XV_FS];
if (Pico32xDrawMode == PDM32X_BOTH)
PicoDrawUpdateHighPal();
if (Pico32xDrawMode == PDM32X_BOTH) {
if (Pico.m.dirtyPal)
PicoDrawUpdateHighPal();
}
if ((Pico32x.vdp_regs[0] & P32XV_Mx) == 2)
{
@ -303,26 +266,33 @@ do_it:
if (Pico32x.vdp_regs[2 / 2] & P32XV_SFT)
lines_sft_offs |= 1 << 8;
do_loop[which_func](Pico.est.DrawLineDest, dram, lines_sft_offs, md_bg);
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 *)DrawLineDestBase32x + offs * DrawLineDestIncrement32x);
unsigned char *pmd = Pico.est.Draw2FB + 328 * offs + 8;
unsigned short *pal = Pico.est.HighPal;
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;
PicoDrawUpdateHighPal();
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 = (unsigned short *)Pico.est.DrawLineDest + poffs;
dst = DrawLineDest + poffs;
}
for (p = 0; p < plen; p += 4) {
dst[p + 0] = pal[*pmd++];
@ -330,7 +300,7 @@ void PicoDraw32xLayerMdOnly(int offs, int lines)
dst[p + 2] = pal[*pmd++];
dst[p + 3] = pal[*pmd++];
}
dst = Pico.est.DrawLineDest = (char *)dst + DrawLineDestIncrement32x;
dst = (void *)((char *)dst + DrawLineDestIncrement);
pmd += 328 - plen;
if (have_scan)
PicoScan32xEnd(l + offs);
@ -339,32 +309,21 @@ void PicoDraw32xLayerMdOnly(int offs, int lines)
void PicoDrawSetOutFormat32x(pdso_t which, int use_32x_line_mode)
{
if (which == PDF_RGB555) {
// CLUT pixels needed as well, for layer priority
PicoDrawSetInternalBuf(Pico.est.Draw2FB, 328);
PicoDrawSetOutBufMD(NULL, 0);
} else {
// store CLUT pixels, same layout as alt renderer
#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);
PicoDrawSetOutBufMD(Pico.est.Draw2FB, 328);
Pico32xDrawMode = PDM32X_OFF;
return;
}
if (use_32x_line_mode)
// we'll draw via FinalizeLine32xRGB555 (rare)
Pico32xDrawMode = PDM32X_OFF;
else
// in RGB555 mode the 32x layer is drawn over the MD layer, in the other
// modes 32x and MD layer are merged together by the 32x renderer
Pico32xDrawMode = (which == PDF_RGB555) ? PDM32X_32X_ONLY : PDM32X_BOTH;
}
void PicoDrawSetOutBuf32X(void *dest, int increment)
{
DrawLineDestBase32x = dest;
DrawLineDestIncrement32x = increment;
// in RGB555 mode this buffer is also used by the MD renderer
if (Pico32xDrawMode != PDM32X_BOTH)
PicoDrawSetOutBufMD(DrawLineDestBase32x, DrawLineDestIncrement32x);
// 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

View file

@ -1,515 +0,0 @@
@*
@* PicoDrive
@* (C) notaz, 2010
@* (C) irixxxx, 2019-2023
@*
@* This work is licensed under the terms of MAME license.
@* See COPYING file in the top-level directory.
@*
#include <pico/arm_features.h>
#include <pico/pico_int_offs.h>
.extern Pico32x
.extern Pico
.equiv P32XV_PRI, (1<< 7)
.text
.align 2
PIC_LDR_INIT()
.macro call_scan_prep cond pico @ &Pico
.if \cond
PIC_LDR(r4, r6, PicoScan32xBegin)
PIC_LDR(r5, r6, PicoScan32xEnd)
add r6, \pico, #OFS_Pico_est
ldr r4, [r4]
ldr r5, [r5]
stmfd sp!, {r4,r5,r6}
.endif
.endm
.macro call_scan_fin_ge cond
.if \cond
addge sp, sp, #4*3
.endif
.endm
.macro call_scan_begin cond
.if \cond
stmfd sp!, {r1-r3}
and r0, r2, #0xff
add r0, r0, r4
mov lr, pc
ldr pc, [sp, #(3+0)*4]
ldr r0, [sp, #(3+2)*4] @ &Pico.est
ldmfd sp!, {r1-r3}
ldr r0, [r0, #OFS_EST_DrawLineDest]
.endif
.endm
.macro call_scan_end cond
.if \cond
stmfd sp!, {r0-r3}
and r0, r2, #0xff
add r0, r0, r4
mov lr, pc
ldr pc, [sp, #(4+1)*4]
ldr r1, [sp, #(4+2)*4] @ &Pico.est
ldr r0, [r1, #OFS_EST_DrawLineDest]
ldr r2, [r1, #OFS_EST_DrawLineDestIncr]
add r0, r0, r2
str r0, [r1, #OFS_EST_DrawLineDest]
ldmfd sp!, {r0-r3}
.endif
.endm
@ direct color
@ unsigned short *dst, unsigned short *dram, int lines_sft_offs, int mdbg
.macro make_do_loop_dc name call_scan do_md
.global \name
\name:
stmfd sp!, {r4-r11,lr}
PIC_LDR(lr, r9, Pico)
PIC_LDR(r10,r9, Pico32x)
ldr r11, [lr, #OFS_Pico_est+OFS_EST_Draw2FB]
ldrh r10,[r10, #0x40] @ Pico32x.vdp_regs[0]
add r9, lr, #OFS_Pico_est+OFS_EST_HighPal @ palmd
and r4, r2, #0xff
mov r5, #328
mov r3, r3, lsl #26 @ mdbg << 26
mla r11,r4,r5,r11 @ r11 = pmd = PicoDraw2FB + offs*328: md data
tst r10,#P32XV_PRI
movne r10,#0
moveq r10,#0x8000 @ r10 = !inv_bit
call_scan_prep \call_scan lr
mov r4, #0 @ line
b 1f @ loop_outer_entry
0: @ loop_outer:
call_scan_end \call_scan
ldr r12, [r9, #OFS_EST_DrawLineDestIncr-OFS_EST_HighPal]
sub r0, r0, #320*2
add r0, r0, r12
add r4, r4, #1
cmp r4, r2, lsr #16
call_scan_fin_ge \call_scan
ldmgefd sp!, {r4-r11,pc}
1: @ loop_outer_entry:
call_scan_begin \call_scan
mov r12,r4, lsl #1
ldrh r12,[r1, r12]
add r11,r11,#8
mov r6, #320/2
add r5, r1, r12, lsl #1 @ p32x = dram + dram[l]
2: @ loop_inner:
@ r4,r6 - counters; r5 - 32x data; r9 - md pal; r10 - inv_prio; r11 - md data
@ r7,r8,r12,lr - temp
ldrh r7, [r5], #2
ldrh r8, [r5], #2
subs r6, r6, #1
blt 0b @ loop_outer
cmp r7, r8
beq 5f @ check_fill
3: @ no_fill:
ldrb r12,[r11], #1 @ MD pixel 0
eor r7, r7, r10
and lr, r7, #0x03e0 @ convert BGR555 -> RGB565
mov r7, r7, ror #5
orr r7, r7, r7, ror #10+11
orr r7, r7, lr, lsl #1+16
eor r8, r8, r10
and lr, r8, #0x03e0
mov r8, r8, ror #5
orr r8, r8, r8, ror #10+11
orr r8, r8, lr, lsl #1+16
ldrb lr, [r11], #1 @ MD pixel 1
.if \do_md
cmp r3, r12, lsl #26
tstne r7, #0x20<<16
movne r12,r12, lsl #1 @ load MD color if no 32X prio and not bg
ldrneh r12,[r9, r12]
moveq r12,r7, lsr #16 @ else replace with 32X color
cmp r3, lr, lsl #26
tstne r8, #0x20<<16
movne lr, lr, lsl #1 @ load MD color if no 32X prio and not bg
ldrneh lr, [r9, lr]
moveq lr, r8, lsr #16 @ else replace with 32X color
orr r12,r12, lr, lsl #16 @ combine 2 pixels to optimize memory bandwidth
str r12,[r0], #4 @ (no write combining on ARM9)
.else
cmp r3, r12, lsl #26 @ replace MD bg info into prio bit
tstne r7, #0x20<<16
moveq r7, r7, lsr #16
streqh r7, [r0, #0]
cmp r3, lr, lsl #26
tstne r8, #0x20<<16
moveq r8, r8, lsr #16
streqh r8, [r0, #2]
add r0, r0, #4 @ store 32x pixels if 32X prio or MD bg
.endif
b 2b @ loop_inner
5: @ check_fill:
@ count pixels, align if needed
ldrh r12,[r5, #0] @ only do this for at least 4 pixels
ldrh lr ,[r5, #2]
cmp r12,r7
cmpeq lr ,r7
bne 3b @ no_fill
add r5, r5, #4 @ adjust for the check above
sub lr, r5, #4+4 @ starting r5 (32x render data start)
add r6, r6, #1 @ restore from dec
6: @ count_loop:
sub r12,r5, lr @ loop checks 2 pixels
ldrh r8, [r5], #2
cmp r12,r6, lsl #2
ldrh r12,[r5], #2
bge 7f @ count_done
cmp r8, r7
cmpeq r12,r7
beq 6b
7: @ count_done:
sub r5, r5, #4 @ undo readahead
sub r8, r5, lr @ pixel count
mov r8, r8, lsr #1
cmp r8, r6, lsl #1 @ limit count to line length
movgt r8, r6, lsl #1
sub r6, r6, r8, lsr #1 @ consume pixels
eor r7, r7, r10
and r12,r7, #0x03e0 @ convert BGR555 -> RGB565
mov r7, r7, ror #5
orr r7, r7, r7, ror #10+11
orr r7, r7, r12,lsl #1+16
mov r7, r7, lsr #16
tst r7, #0x20 @ check for prio transfer
bne 9f @ bg_loop
add r11,r11,r8 @ consume md pixels (not used)
orr r12,r7, r7, lsl #16
mov r7 ,r12
8: @ 32x_loop:
subs r8, r8, #4 @ store 4 pixels
stmgeia r0!, {r7, r12}
bgt 8b @ 32x_loop
beq 2b @ loop_inner
adds r8, r8, #2
strge r7, [r0], #4 @ store 2 leftover pixels
b 2b @ loop_inner
9: @ bg_loop:
ldrb r12,[r11],#1 @ MD pixel 0,1
ldrb lr, [r11],#1
.if \do_md
cmp r3, r12,lsl #26 @ MD pixel 0 has bg?
mov r12,r12,lsl #1
ldrneh r12,[r9, r12] @ t = palmd[*pmd]
moveq r12,r7
cmp r3, lr, lsl #26 @ MD pixel 1 has bg?
mov lr, lr, lsl #1
ldrneh lr, [r9, lr]
moveq lr, r7
orr r12,r12,lr, lsl #16 @ combine 2 pixels to optimize memory bandwidth
str r12,[r0], #4 @ (no write combining on ARM9)
.else
add r0, r0, #4
cmp r3, r12,lsl #26 @ MD pixel 0 has bg?
streqh r7, [r0, #-4]
cmp r3, lr, lsl #26 @ MD pixel 1 has bg?
streqh r7, [r0, #-2]
.endif
subs r8, r8, #2
bgt 9b @ bg_loop
b 2b @ loop_inner
.endm
@ packed pixel
@ note: this may read a few bytes over the end of PicoDraw2FB and dram,
@ so those should have a bit more alloc'ed than really needed.
@ unsigned short *dst, unsigned short *dram, int lines_sft_offs, int mdbg
.macro make_do_loop_pp name call_scan do_md
.global \name
\name:
stmfd sp!, {r4-r11,lr}
PIC_LDR(lr, r9, Pico)
PIC_LDR(r10,r9, Pico32xMem)
ldr r9, =OFS_PMEM32x_pal_native
ldr r10, [r10]
ldr r11, [lr, #OFS_Pico_est+OFS_EST_Draw2FB]
add r10,r10,r9
add r9, lr, #OFS_Pico_est+OFS_EST_HighPal @ palmd
and r4, r2, #0xff
mov r5, #328
mov r3, r3, lsl #26 @ mdbg << 26
mla r11,r4,r5,r11 @ r11 = pmd = PicoDraw2FB + offs*328: md data
call_scan_prep \call_scan lr
mov r4, #0 @ line
b 1f @ loop_outer_entry
0: @ loop_outer:
call_scan_end \call_scan
ldr r12, [r9, #OFS_EST_DrawLineDestIncr-OFS_EST_HighPal]
sub r0, r0, #320*2
add r0, r0, r12
add r4, r4, #1
cmp r4, r2, lsr #16
call_scan_fin_ge \call_scan
ldmgefd sp!, {r4-r11,pc}
1: @ loop_outer_entry:
call_scan_begin \call_scan
mov r12,r4, lsl #1
ldrh r12,[r1, r12]
add r11,r11,#8
mov r6, #320/2
add r5, r1, r12, lsl #1 @ p32x = dram + dram[l]
and r12,r2, #0x100 @ shift
add r5, r5, r12,lsr #8
2: @ loop_inner:
@ r4,r6 - counters; r5 - 32x data; r9,r10 - md,32x pal; r11 - md data
@ r7,r8,r12,lr - temp
tst r5, #1
ldreqb r8, [r5], #2
ldrb r7, [r5, #-1]
ldrneb r8, [r5, #2]! @ r7,r8 - 32X pixel 0,1
subs r6, r6, #1
blt 0b @ loop_outer
cmp r7, r8
beq 5f @ check_fill
3: @ no_fill:
ldrb r12,[r11], #1 @ MD pixel 0
ldrb lr, [r11], #1 @ MD pixel 1
mov r7, r7, lsl #1
mov r8, r8, lsl #1
ldrh r7, [r10,r7] @ 32X color 0
ldrh r8, [r10,r8] @ 32X color 1
.if \do_md
cmp r3, r12, lsl #26
movne r12,r12, lsl #1 @ load MD color if not bg
ldrneh r12,[r9, r12]
orreq r7, r7, #0x20 @ accumulate MD bg info into prio bit
cmp r3, lr, lsl #26
movne lr, lr, lsl #1
ldrneh lr, [r9, lr]
orreq r8, r8, #0x20
tst r7, #0x20 @ replace 32X with MD color if no prio and not bg
moveq r7, r12
tst r8, #0x20
moveq r8, lr
orr r7, r7, r8, lsl #16 @ combine 2 pixels to optimize memory bandwidth
str r7, [r0], #4 @ (no write combining on ARM9)
.else
cmp r3, r12, lsl #26 @ replace MD bg info into prio bit
orreq r7, r7, #0x20
cmp r3, lr, lsl #26
orreq r8, r8, #0x20
add r0, r0, #4 @ store 32x pixels if 32X prio or MD bg
tst r7, #0x20
strneh r7, [r0, #-4]
tst r8, #0x20
strneh r8, [r0, #-2]
.endif
b 2b @ loop_inner
5: @ check_fill:
@ count pixels, align if needed
bic r12,r5, #1
ldrh r12,[r12, #0] @ only do this for at least 4 pixels
orr lr, r7, r7, lsl #8
cmp r12,lr
bne 3b @ no_fill
add r5, r5, #2 @ adjust for the check above
sub lr, r5, #4 @ starting r5 (32x render data start)
bic r5, r5, #1
add r6, r6, #1 @ restore from dec
orr r7, r7, r7, lsl #8
6: @ count_loop:
sub r12,r5, lr @ loop checks 4 pixels
ldrh r8, [r5], #2
cmp r12,r6, lsl #1
ldrh r12,[r5], #2
bge 7f @ count_done
cmp r8, r7
cmpeq r12,r7
beq 6b
cmp r8, r7
addeq r5, r5, #2 @ adjust if 2 pixels where ok
7: @ count_done:
sub r5, r5, #4 @ undo readahead
tst lr, #1 @ fix alignment and calculate count
subne r5, r5, #1
sub r8, r5, lr
and r7, r7, #0xff @ 32x pixel color
mov r7, r7, lsl #1
ldrh r7, [r10,r7]
cmp r8, r6, lsl #1 @ limit count to line length
movgt r8, r6, lsl #1
sub r6, r6, r8, lsr #1 @ consume pixels
tst r7, #0x20 @ check for prio transfer
beq 9f @ bg_loop
add r11,r11,r8 @ consume md pixels (not used)
orr r12,r7, r7, lsl #16
mov r7 ,r12
8: @ 32x_loop:
subs r8, r8, #4 @ store 4 pixels
stmgeia r0!, {r7, r12}
bgt 8b @ 32x_loop
beq 2b @ loop_inner
adds r8, r8, #2
strge r7, [r0], #4 @ store 2 leftover pixels
b 2b @ loop_inner
9: @ bg_loop:
ldrb r12,[r11],#1 @ MD pixel 0,1
ldrb lr, [r11],#1
.if \do_md
cmp r3, r12,lsl #26 @ MD pixel 0 has bg?
mov r12,r12,lsl #1
ldrneh r12,[r9, r12] @ t = palmd[*pmd]
moveq r12,r7
cmp r3, lr, lsl #26 @ MD pixel 1 has bg?
mov lr, lr, lsl #1
ldrneh lr, [r9, lr]
moveq lr, r7
orr r12,r12,lr, lsl #16 @ combine 2 pixels to optimize memory bandwidth
str r12,[r0], #4 @ (no write combining on ARM9)
.else
add r0, r0, #4
cmp r3, r12,lsl #26 @ MD pixel 0 has bg?
streqh r7, [r0, #-4]
cmp r3, lr, lsl #26 @ MD pixel 1 has bg?
streqh r7, [r0, #-2]
.endif
subs r8, r8, #2
bgt 9b @ bg_loop
b 2b @ loop_inner
.endm
@ run length
@ unsigned short *dst, unsigned short *dram, int lines_sft_offs, int mdbg
.macro make_do_loop_rl name call_scan do_md
.global \name
\name:
stmfd sp!, {r4-r11,lr}
PIC_LDR(lr, r9, Pico)
PIC_LDR(r10,r9, Pico32xMem)
ldr r9, =OFS_PMEM32x_pal_native
ldr r10, [r10]
ldr r11, [lr, #OFS_Pico_est+OFS_EST_Draw2FB]
add r10,r10,r9
add r9, lr, #OFS_Pico_est+OFS_EST_HighPal @ palmd
and r4, r2, #0xff
mov r5, #328
mov r3, r3, lsl #26 @ mdbg << 26
mla r11,r4,r5,r11 @ r11 = pmd = PicoDraw2FB + offs*328: md data
call_scan_prep \call_scan lr
mov r4, #0 @ line
b 1f @ loop_outer_entry
0: @ loop_outer:
call_scan_end \call_scan
ldr r12, [r9, #OFS_EST_DrawLineDestIncr-OFS_EST_HighPal]
sub r0, r0, #320*2
add r0, r0, r12
add r4, r4, #1
cmp r4, r2, lsr #16
call_scan_fin_ge \call_scan
ldmgefd sp!, {r4-r11,pc}
1: @ loop_outer_entry:
call_scan_begin \call_scan
mov r12,r4, lsl #1
ldrh r12,[r1, r12]
add r11,r11,#8
mov r6, #320
add r5, r1, r12, lsl #1 @ p32x = dram + dram[l]
2: @ loop_inner:
ldrh r8, [r5], #2 @ control word
and r12,r8, #0xff
mov r12,r12,lsl #1
ldrh lr, [r10,r12] @ t = 32x pixel
eor lr, lr, #0x20
3: @ loop_innermost:
subs r6, r6, #1
ldrgeb r7, [r11], #1 @ MD pixel
blt 0b @ loop_outer
tst lr, #0x20
cmpne r3, r7, lsl #26 @ MD has bg pixel?
.if \do_md
mov r7, r7, lsl #1
ldrneh r12,[r9, r7] @ t = palmd[*pmd]
streqh lr, [r0], #2
strneh r12,[r0], #2 @ *dst++ = t
.else
streqh lr, [r0]
add r0, r0, #2
.endif
subs r8, r8, #0x100
bge 3b @ loop_innermost
b 2b @ loop_inner
.endm
make_do_loop_dc do_loop_dc, 0, 0
make_do_loop_dc do_loop_dc_md, 0, 1
make_do_loop_dc do_loop_dc_scan, 1, 0
make_do_loop_dc do_loop_dc_scan_md, 1, 1
.pool
make_do_loop_pp do_loop_pp, 0, 0
make_do_loop_pp do_loop_pp_md, 0, 1
make_do_loop_pp do_loop_pp_scan, 1, 0
make_do_loop_pp do_loop_pp_scan_md, 1, 1
.pool
make_do_loop_rl do_loop_rl, 0, 0
make_do_loop_rl do_loop_rl_md, 0, 1
make_do_loop_rl do_loop_rl_scan, 1, 0
make_do_loop_rl do_loop_rl_scan_md, 1, 1
.pool
@ vim:filetype=armasm

373
pico/32x/draw_arm.s Normal file
View file

@ -0,0 +1,373 @@
@*
@* PicoDrive
@* (C) notaz, 2010
@*
@* This work is licensed under the terms of MAME license.
@* See COPYING file in the top-level directory.
@*
.extern Pico32x
.extern PicoDraw2FB
.extern HighPal
.equiv P32XV_PRI, (1<< 7)
.bss
.align 2
.global Pico32xNativePal
Pico32xNativePal:
.word 0
.text
.align 2
.macro call_scan_prep cond
.if \cond
ldr r4, =PicoScan32xBegin
ldr r5, =PicoScan32xEnd
ldr r6, =DrawLineDest
ldr r4, [r4]
ldr r5, [r5]
stmfd sp!, {r4,r5,r6}
.endif
.endm
.macro call_scan_fin_ge cond
.if \cond
addge sp, sp, #4*3
.endif
.endm
.macro call_scan_begin cond
.if \cond
stmfd sp!, {r1-r3}
and r0, r2, #0xff
add r0, r0, r4
mov lr, pc
ldr pc, [sp, #(3+0)*4]
ldr r0, [sp, #(3+2)*4] @ &DrawLineDest
ldmfd sp!, {r1-r3}
ldr r0, [r0]
.endif
.endm
.macro call_scan_end cond
.if \cond
stmfd sp!, {r0-r3}
and r0, r2, #0xff
add r0, r0, r4
mov lr, pc
ldr pc, [sp, #(4+1)*4]
ldmfd sp!, {r0-r3}
.endif
.endm
@ direct color
@ unsigned short *dst, unsigned short *dram, int lines_sft_offs, int mdbg
.macro make_do_loop_dc name call_scan do_md
.global \name
\name:
stmfd sp!, {r4-r11,lr}
ldr r10,=Pico32x
ldr r11,=PicoDraw2FB
ldr r10,[r10, #0x40] @ Pico32x.vdp_regs[0]
ldr r11,[r11]
ldr r9, =HighPal @ palmd
and r4, r2, #0xff
mov r5, #328
lsl r3, #26 @ mdbg << 26
mla r11,r4,r5,r11 @ r11 = pmd = PicoDraw2FB + offs*328: md data
tst r10,#P32XV_PRI
moveq r10,#0
movne r10,#0x8000 @ r10 = inv_bit
call_scan_prep \call_scan
mov r4, #0 @ line
b 1f @ loop_outer_entry
0: @ loop_outer:
call_scan_end \call_scan
add r4, r4, #1
sub r11,r11,#1 @ adjust for prev read
cmp r4, r2, lsr #16
call_scan_fin_ge \call_scan
ldmgefd sp!, {r4-r11,pc}
1: @ loop_outer_entry:
call_scan_begin \call_scan
mov r12,r4, lsl #1
ldrh r12,[r1, r12]
add r11,r11,#8
mov r6, #320
add r5, r1, r12, lsl #1 @ p32x = dram + dram[l]
2: @ loop_inner:
ldrb r7, [r11], #1 @ MD pixel
subs r6, r6, #1
blt 0b @ loop_outer
ldrh r8, [r5], #2 @ 32x pixel
cmp r3, r7, lsl #26 @ MD has bg pixel?
beq 3f @ draw32x
eor r12,r8, r10
ands r12,r12,#0x8000 @ !((t ^ inv) & 0x8000)
.if \do_md
mov r7, r7, lsl #1
ldreqh r12,[r9, r7]
streqh r12,[r0], #2 @ *dst++ = palmd[*pmd]
.endif
beq 2b @ loop_inner
3: @ draw32x:
and r12,r8, #0x03e0
mov r8, r8, lsl #11
orr r8, r8, r8, lsr #(10+11)
orr r8, r8, r12,lsl #1
bic r8, r8, #0x0020 @ kill prio bit
strh r8, [r0], #2 @ *dst++ = bgr2rgb(*p32x++)
b 2b @ loop_inner
.endm
@ packed pixel
@ note: this may read a few bytes over the end of PicoDraw2FB and dram,
@ so those should have a bit more alloc'ed than really needed.
@ unsigned short *dst, unsigned short *dram, int lines_sft_offs, int mdbg
.macro make_do_loop_pp name call_scan do_md
.global \name
\name:
stmfd sp!, {r4-r11,lr}
ldr r11,=PicoDraw2FB
ldr r10,=Pico32xNativePal
ldr r11,[r11]
ldr r10,[r10]
ldr r9, =HighPal @ palmd
and r4, r2, #0xff
mov r5, #328
lsl r3, #26 @ mdbg << 26
mla r11,r4,r5,r11 @ r11 = pmd = PicoDraw2FB + offs*328: md data
call_scan_prep \call_scan
mov r4, #0 @ line
b 1f @ loop_outer_entry
0: @ loop_outer:
call_scan_end \call_scan
add r4, r4, #1
cmp r4, r2, lsr #16
call_scan_fin_ge \call_scan
ldmgefd sp!, {r4-r11,pc}
1: @ loop_outer_entry:
call_scan_begin \call_scan
mov r12,r4, lsl #1
ldrh r12,[r1, r12]
add r11,r11,#8
mov r6, #320/2
add r5, r1, r12, lsl #1 @ p32x = dram + dram[l]
and r12,r2, #0x100 @ shift
add r5, r5, r12,lsr #8
2: @ loop_inner:
@ r4,r6 - counters; r5 - 32x data; r9,r10 - md,32x pal; r11 - md data
@ r7,r8,r12,lr - temp
tst r5, #1
ldreqb r8, [r5], #2
ldrb r7, [r5, #-1]
ldrneb r8, [r5, #2]! @ r7,r8 - pixel 0,1 index
subs r6, r6, #1
blt 0b @ loop_outer
cmp r7, r8
beq 5f @ check_fill @ +8
3: @ no_fill:
mov r12,r7, lsl #1
mov lr, r8, lsl #1
ldrh r7, [r10,r12]
ldrh r8, [r10,lr]
add r11,r11,#2
eor r12,r7, #0x20
tst r12,#0x20
ldrneb r12,[r11,#-2] @ MD pixel 0
eor lr, r8, #0x20
cmpne r3, r12, lsl #26 @ MD has bg pixel?
.if \do_md
mov r12,r12,lsl #1
ldrneh r7, [r9, r12] @ t = palmd[pmd[0]]
tst lr, #0x20
ldrneb lr, [r11,#-1] @ MD pixel 1
strh r7, [r0], #2
cmpne r3, lr, lsl #26 @ MD has bg pixel?
mov lr, lr, lsl #1
ldrneh r8, [r9, lr] @ t = palmd[pmd[1]]
strh r8, [r0], #2
.else
streqh r7, [r0]
tst lr, #0x20
ldrneb lr, [r11,#-1] @ MD pixel 1
add r0, r0, #4
cmpne r3, lr, lsl #26 @ MD has bg pixel?
streqh r8, [r0, #-2]
.endif
b 2b @ loop_inner
5: @ check_fill
@ count pixels, align if needed
bic r12,r5, #1
ldrh r12,[r12]
orr lr, r7, r7, lsl #8
cmp r12,lr
bne 3b @ no_fill
tst r5, #1
sub lr, r5, #2 @ starting r5 (32x render data start)
addeq r5, r5, #2
addne r5, r5, #1 @ add for the check above
add r6, r6, #1 @ restore from dec
orr r7, r7, r7, lsl #8
6:
sub r12,r5, lr
ldrh r8, [r5], #2
cmp r12,r6, lsl #1
ldrh r12,[r5], #2
bge 7f @ count_done
cmp r8, r7
cmpeq r12,r7
beq 6b
7: @ count_done
sub r5, r5, #4 @ undo readahead
@ fix alignment and check type
sub r8, r5, lr
tst r8, #1
subne r5, r5, #1
subne r8, r8, #1
and r7, r7, #0xff
cmp r8, r6, lsl #1
mov r7, r7, lsl #1
movgt r8, r6, lsl #1 @ r8=count
ldrh r7, [r10,r7]
sub r6, r6, r8, lsr #1 @ adjust counter
tst r7, #0x20
beq 9f @ bg_mode
add r11,r11,r8
8:
subs r8, r8, #2
strgeh r7, [r0], #2
strgeh r7, [r0], #2
bgt 8b
b 2b @ loop_inner
9: @ bg_mode:
ldrb r12,[r11],#1 @ MD pixel
ldrb lr, [r11],#1
cmp r3, lr, lsl #26 @ MD has bg pixel?
.if \do_md
mov r12,r12,lsl #1
ldrneh r12,[r9, r12] @ t = palmd[*pmd]
moveq r12,r7
cmp r3, lr, lsl #26
mov lr, lr, lsl #1
ldrneh lr, [r9, lr]
moveq lr, r7
strh r12,[r0], #2
strh lr, [r0], #2
.else
streqh r7, [r0]
cmp r3, lr, lsl #26
streqh r7, [r0, #2]
add r0, r0, #4
.endif
subs r8, r8, #2
bgt 9b @ bg_mode
b 2b @ loop_inner
.endm
@ run length
@ unsigned short *dst, unsigned short *dram, int lines_sft_offs, int mdbg
.macro make_do_loop_rl name call_scan do_md
.global \name
\name:
stmfd sp!, {r4-r11,lr}
ldr r11,=PicoDraw2FB
ldr r10,=Pico32xNativePal
ldr r11,[r11]
ldr r10,[r10]
ldr r9, =HighPal @ palmd
and r4, r2, #0xff
mov r5, #328
lsl r3, #26 @ mdbg << 26
mla r11,r4,r5,r11 @ r11 = pmd = PicoDraw2FB + offs*328: md data
call_scan_prep \call_scan
mov r4, #0 @ line
b 1f @ loop_outer_entry
0: @ loop_outer:
call_scan_end \call_scan
add r4, r4, #1
sub r11,r11,#1 @ adjust for prev read
cmp r4, r2, lsr #16
call_scan_fin_ge \call_scan
ldmgefd sp!, {r4-r11,pc}
1: @ loop_outer_entry:
call_scan_begin \call_scan
mov r12,r4, lsl #1
ldrh r12,[r1, r12]
add r11,r11,#8
mov r6, #320
add r5, r1, r12, lsl #1 @ p32x = dram + dram[l]
2: @ loop_inner:
ldrh r8, [r5], #2 @ control word
and r12,r8, #0xff
mov r12,r12,lsl #1
ldrh lr, [r10,r12] @ t = 32x pixel
eor lr, lr, #0x20
3: @ loop_innermost:
ldrb r7, [r11], #1 @ MD pixel
subs r6, r6, #1
blt 0b @ loop_outer
cmp r3, r7, lsl #26 @ MD has bg pixel?
mov r7, r7, lsl #1
tstne lr, #0x20
.if \do_md
ldrneh r12,[r9, r7] @ t = palmd[*pmd]
streqh lr, [r0], #2
strneh r12,[r0], #2 @ *dst++ = t
.else
streqh lr, [r0]
add r0, r0, #2
.endif
subs r8, r8, #0x100
bge 3b @ loop_innermost
b 2b @ loop_inner
.endm
make_do_loop_dc do_loop_dc, 0, 0
make_do_loop_dc do_loop_dc_md, 0, 1
make_do_loop_dc do_loop_dc_scan, 1, 0
make_do_loop_dc do_loop_dc_scan_md, 1, 1
make_do_loop_pp do_loop_pp, 0, 0
make_do_loop_pp do_loop_pp_md, 0, 1
make_do_loop_pp do_loop_pp_scan, 1, 0
make_do_loop_pp do_loop_pp_scan_md, 1, 1
make_do_loop_rl do_loop_rl, 0, 0
make_do_loop_rl do_loop_rl_md, 0, 1
make_do_loop_rl do_loop_rl_scan, 1, 0
make_do_loop_rl do_loop_rl_scan_md, 1, 1
@ vim:filetype=armasm

File diff suppressed because it is too large Load diff

View file

@ -1,288 +0,0 @@
/*
* PicoDrive 32X memory access functions, assembler version
* (C) irixxxx, 2018-2021
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <pico/pico_int_offs.h>
@ 32X bank sizes... TODO this should somehow come from an include file
.equ SH2_ROM_SHIFT, 10 @ 0x003fffff
.equ SH2_RAM_SHIFT, 14 @ 0x0003ffff
.equ SH2_DRAM_SHIFT,15 @ 0x0001ffff
.equ SH2_DA_SHIFT, 20 @ 0x00000fff
.equ SH2_DRAM_OW, 1<<(32-SH2_DRAM_SHIFT) @ DRAM overwrite mode bit
.text
.align 5
#if 0
@ u32 a, SH2 *sh2
.global sh2_read8_rom
.global sh2_read8_sdram
.global sh2_read8_da
.global sh2_read8_dram
.global sh2_read16_rom
.global sh2_read16_sdram
.global sh2_read16_da
.global sh2_read16_dram
.global sh2_read32_rom
.global sh2_read32_sdram
.global sh2_read32_da
.global sh2_read32_dram
#endif
@ u32 a, u32 d, SH2 *sh2
.global sh2_write8_sdram
.global sh2_write8_da
.global sh2_write8_dram
.global sh2_write16_sdram
.global sh2_write16_da
.global sh2_write16_dram
.global sh2_write32_sdram
.global sh2_write32_da
.global sh2_write32_dram
#if 0
sh2_read8_rom:
ldr ip, [r1, #OFS_SH2_p_rom]
eor r0, r0, #1
mov r0, r0, lsl #SH2_ROM_SHIFT
ldrb r0, [ip, r0, lsr #SH2_ROM_SHIFT]
bx lr
sh2_read8_sdram:
ldr ip, [r1, #OFS_SH2_p_sdram]
eor r0, r0, #1
mov r0, r0, lsl #SH2_RAM_SHIFT
ldrb r0, [ip, r0, lsr #SH2_RAM_SHIFT]
bx lr
sh2_read8_da:
ldr ip, [r1, #OFS_SH2_p_da]
eor r0, r0, #1
mov r0, r0, lsl #SH2_DA_SHIFT
ldrb r0, [ip, r0, lsr #SH2_DA_SHIFT]
bx lr
sh2_read8_dram:
ldr ip, [r1, #OFS_SH2_p_dram]
eor r0, r0, #1
mov r0, r0, lsl #SH2_DRAM_SHIFT
ldrb r0, [ip, r0, lsr #SH2_DRAM_SHIFT]
bx lr
sh2_read16_rom:
ldr ip, [r1, #OFS_SH2_p_rom]
mov r0, r0, lsl #SH2_ROM_SHIFT
mov r0, r0, lsr #SH2_ROM_SHIFT
ldrh r0, [ip, r0]
bx lr
sh2_read16_sdram:
ldr ip, [r1, #OFS_SH2_p_sdram]
mov r0, r0, lsl #SH2_RAM_SHIFT
mov r0, r0, lsr #SH2_RAM_SHIFT
ldrh r0, [ip, r0]
bx lr
sh2_read16_da:
ldr ip, [r1, #OFS_SH2_p_da]
mov r0, r0, lsl #SH2_DA_SHIFT
mov r0, r0, lsr #SH2_DA_SHIFT
ldrh r0, [ip, r0]
bx lr
sh2_read16_dram:
ldr ip, [r1, #OFS_SH2_p_dram]
mov r0, r0, lsl #SH2_DRAM_SHIFT
mov r0, r0, lsr #SH2_DRAM_SHIFT
ldrh r0, [ip, r0]
bx lr
sh2_read32_rom:
ldr ip, [r1, #OFS_SH2_p_rom]
mov r0, r0, lsl #SH2_ROM_SHIFT
ldr r0, [ip, r0, lsr #SH2_ROM_SHIFT]
mov r0, r0, ror #16
bx lr
sh2_read32_sdram:
ldr ip, [r1, #OFS_SH2_p_sdram]
mov r0, r0, lsl #SH2_RAM_SHIFT
ldr r0, [ip, r0, lsr #SH2_RAM_SHIFT]
mov r0, r0, ror #16
bx lr
sh2_read32_da:
ldr ip, [r1, #OFS_SH2_p_da]
mov r0, r0, lsl #SH2_DA_SHIFT
ldr r0, [ip, r0, lsr #SH2_DA_SHIFT]
mov r0, r0, ror #16
bx lr
sh2_read32_dram:
ldr ip, [r1, #OFS_SH2_p_dram]
mov r0, r0, lsl #SH2_DRAM_SHIFT
ldr r0, [ip, r0, lsr #SH2_DRAM_SHIFT]
mov r0, r0, ror #16
bx lr
#endif
sh2_write8_sdram:
@ preserve r0-r2 for tail call
ldr ip, [r2, #OFS_SH2_p_sdram]
eor r3, r0, #1
mov r3, r3, lsl #SH2_RAM_SHIFT
strb r1, [ip, r3, lsr #SH2_RAM_SHIFT]
#ifdef DRC_SH2
ldr r1, [r2, #OFS_SH2_p_drcblk_ram]
ldrb r3, [r1, r3, lsr #SH2_RAM_SHIFT+1]
cmp r3, #0
bxeq lr
@ need to load aligned 16 bit data for check
bic r0, r0, #1
mov r1, r0, lsl #SH2_RAM_SHIFT
mov r1, r1, lsr #SH2_RAM_SHIFT
ldrh r1, [ip, r1]
b sh2_sdram_checks
#else
bx lr
#endif
sh2_write8_da:
@ preserve r0 and r2 for tail call
ldr ip, [r2, #OFS_SH2_p_da]
eor r3, r0, #1
mov r3, r3, lsl #SH2_DA_SHIFT
strb r1, [ip, r3, lsr #SH2_DA_SHIFT]
#ifdef DRC_SH2
ldr ip, [r2, #OFS_SH2_p_drcblk_da]
ldrb r1, [ip, r3, lsr #SH2_DA_SHIFT+1]
bic r0, r0, #1
cmp r1, #0
bxeq lr
mov r1, #2
b sh2_drc_wcheck_da
#else
bx lr
#endif
sh2_write8_dram:
tst r1, #0xff
ldrne ip, [r2, #OFS_SH2_p_dram]
eorne r3, r0, #1
movne r3, r3, lsl #SH2_DRAM_SHIFT
strneb r1, [ip, r3, lsr #SH2_DRAM_SHIFT]
bx lr
sh2_write16_sdram:
@ preserve r0-r2 for tail call
ldr ip, [r2, #OFS_SH2_p_sdram]
mov r3, r0, lsl #SH2_RAM_SHIFT
mov r3, r3, lsr #SH2_RAM_SHIFT
strh r1, [ip, r3]
#ifdef DRC_SH2
ldr ip, [r2, #OFS_SH2_p_drcblk_ram]
ldrb r3, [ip, r3, lsr #1]
cmp r3, #0
bxeq lr
b sh2_sdram_checks
#else
bx lr
#endif
sh2_write16_da:
@ preserve r0 and r2 for tail call
ldr ip, [r2, #OFS_SH2_p_da]
mov r3, r0, lsl #SH2_DA_SHIFT
mov r3, r3, lsr #SH2_DA_SHIFT
strh r1, [ip, r3]
#ifdef DRC_SH2
ldr ip, [r2, #OFS_SH2_p_drcblk_da]
ldrb r1, [ip, r3, lsr #1]
cmp r1, #0
bxeq lr
mov r1, #2
b sh2_drc_wcheck_da
#else
bx lr
#endif
sh2_write16_dram:
ldr ip, [r2, #OFS_SH2_p_dram]
tst r0, #SH2_DRAM_OW
mov r3, r0, lsl #SH2_DRAM_SHIFT
mov r3, r3, lsr #SH2_DRAM_SHIFT
streqh r1, [ip, r3]
bxeq lr
add ip, ip, r3
tst r1, #0xff
strneb r1, [ip, #0]
tst r1, #0xff00
movne r1, r1, lsr #8
strneb r1, [ip, #1]
bx lr
sh2_write32_sdram:
@ preserve r0-r2 for tail call
ldr ip, [r2, #OFS_SH2_p_sdram]
mov r1, r1, ror #16
mov r3, r0, lsl #SH2_RAM_SHIFT
str r1, [ip, r3, lsr #SH2_RAM_SHIFT]
#ifdef DRC_SH2
ldr ip, [r2, #OFS_SH2_p_drcblk_ram]
ldrb r3, [ip, r3, lsr #SH2_RAM_SHIFT+1]!
ldrb ip, [ip, #1]
orrs r3, r3, ip, lsl #16
bxeq lr
mov r1, r1, ror #16
b sh2_sdram_checks_l
#else
bx lr
#endif
sh2_write32_da:
@ preserve r0 and r2 for tail call
ldr ip, [r2, #OFS_SH2_p_da]
mov r1, r1, ror #16
mov r3, r0, lsl #SH2_DA_SHIFT
str r1, [ip, r3, lsr #SH2_DA_SHIFT]
#ifdef DRC_SH2
ldr ip, [r2, #OFS_SH2_p_drcblk_da]
ldrb r1, [ip, r3, lsr #SH2_DA_SHIFT+1]!
ldrb ip, [ip, #1]
orrs r1, r1, ip, lsl #16
bxeq lr
mov r1, #4
b sh2_drc_wcheck_da
#else
bx lr
#endif
sh2_write32_dram:
ldr ip, [r2, #OFS_SH2_p_dram]
tst r0, #SH2_DRAM_OW
mov r3, r0, lsl #SH2_DRAM_SHIFT
mov r1, r1, ror #16
streq r1, [ip, r3, lsr #SH2_DRAM_SHIFT]
bxeq lr
ldr r0, [ip, r3, lsr #SH2_DRAM_SHIFT]
tst r1, #0x00ff0000
bicne r0, r0, #0x00ff0000
tst r1, #0xff000000
bicne r0, r0, #0xff000000
tst r1, #0x000000ff
bicne r0, r0, #0x000000ff
tst r1, #0x0000ff00
bicne r0, r0, #0x0000ff00
orr r0, r0, r1
str r0, [ip, r3, lsr #SH2_DRAM_SHIFT]
bx lr
.pool
@ vim:filetype=armasm

View file

@ -1,57 +1,46 @@
/*
* PicoDrive
* (C) notaz, 2009,2010,2013
* (C) irixxxx, 2019-2023
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
static struct {
int cycles;
unsigned mult;
int ptr;
int irq_reload;
int doing_fifo;
int silent;
int irq_timer;
int irq_state;
short current[2];
} pwm;
enum { PWM_IRQ_LOCKED, PWM_IRQ_STOPPED, PWM_IRQ_LOW, PWM_IRQ_HIGH };
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];
int pwm_irq_opt = PicoIn.opt & POPT_PWM_IRQ_OPT;
cycles = (cycles - 1) & 0x0fff;
pwm.cycles = cycles;
pwm_cycles = cycles;
// supposedly we should stop FIFO when xMd is 0,
// but mars test disagrees
pwm.mult = 0;
pwm_mult = 0;
if ((control & 0x0f) != 0)
pwm.mult = (0x10000<<8) / (cycles+1);
pwm_mult = 0x10000 / cycles;
pwm.irq_timer = (control & 0x0f00) >> 8;
pwm.irq_timer = ((pwm.irq_timer - 1) & 0x0f) + 1;
pwm.irq_reload = pwm.irq_timer;
pwm.irq_state = pwm_irq_opt ? PWM_IRQ_STOPPED: PWM_IRQ_LOCKED;
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;
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(NULL, m68k_cycles, P32XI_PWM);
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);
p32x_event_schedule(m68k_cycles, P32X_EVENT_PWM, pwm_cycles / 3 + 1);
// note: might recurse
p32x_dreq1_trigger();
}
@ -59,14 +48,16 @@ static void do_pwm_irq(SH2 *sh2, unsigned int m68k_cycles)
static int convert_sample(unsigned int v)
{
if (v > pwm.cycles)
v = pwm.cycles;
return (v * pwm.mult >> 8) - 0x10000/2;
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) \
if (cycles_diff >= pwm_cycles) \
consume_fifo_do(sh2, m68k_cycles, cycles_diff); \
}
@ -78,70 +69,67 @@ static void consume_fifo_do(SH2 *sh2, unsigned int m68k_cycles,
unsigned short *fifo_r = mem->pwm_fifo[1];
int sum = 0;
if (pwm.cycles == 0 || pwm.doing_fifo)
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);
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;
pwm_doing_fifo = 1;
while (sh2_cycles_diff >= pwm.cycles)
for (; sh2_cycles_diff >= pwm_cycles; sh2_cycles_diff -= pwm_cycles)
{
sh2_cycles_diff -= pwm.cycles;
if (Pico32x.pwm_p[0] > 0) {
mem->pwm_index[0] = (mem->pwm_index[0]+1) % 4;
fifo_l[0] = fifo_l[1];
fifo_l[1] = fifo_l[2];
fifo_l[2] = fifo_l[3];
Pico32x.pwm_p[0]--;
pwm.current[0] = convert_sample(fifo_l[mem->pwm_index[0]]);
sum |= (u16)pwm.current[0];
mem->pwm_current[0] = convert_sample(fifo_l[0]);
sum += mem->pwm_current[0];
}
if (Pico32x.pwm_p[1] > 0) {
mem->pwm_index[1] = (mem->pwm_index[1]+1) % 4;
fifo_r[0] = fifo_r[1];
fifo_r[1] = fifo_r[2];
fifo_r[2] = fifo_r[3];
Pico32x.pwm_p[1]--;
pwm.current[1] = convert_sample(fifo_r[mem->pwm_index[1]]);
sum |= (u16)pwm.current[1];
mem->pwm_current[1] = convert_sample(fifo_r[0]);
sum += mem->pwm_current[1];
}
mem->pwm[pwm.ptr * 2 ] = pwm.current[0];
mem->pwm[pwm.ptr * 2 + 1] = pwm.current[1];
pwm.ptr = (pwm.ptr + 1) & (PWM_BUFF_LEN - 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;
if (--Pico32x.pwm_irq_cnt == 0) {
Pico32x.pwm_irq_cnt = pwm_irq_reload;
do_pwm_irq(sh2, m68k_cycles);
} else if (Pico32x.pwm_p[1] == 0 && pwm.irq_state >= PWM_IRQ_LOW) {
// buffer underrun. Reduce reload rate if above programmed setting.
if (pwm.irq_reload > pwm.irq_timer)
pwm.irq_reload--;
pwm.irq_state = PWM_IRQ_LOW;
}
}
Pico32x.pwm_cycle_p = m68k_cycles * 3 - sh2_cycles_diff;
pwm.doing_fifo = 0;
pwm_doing_fifo = 0;
if (sum != 0)
pwm.silent = 0;
pwm_silent = 0;
}
static int p32x_pwm_schedule_(SH2 *sh2, unsigned int m68k_now)
{
unsigned int pwm_now = m68k_now * 3;
unsigned int sh2_now = m68k_now * 3;
int cycles_diff_sh2;
if (pwm.cycles == 0)
if (pwm_cycles == 0)
return 0;
cycles_diff_sh2 = pwm_now - Pico32x.pwm_cycle_p;
if (cycles_diff_sh2 >= pwm.cycles)
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 = pwm_now - Pico32x.pwm_cycle_p;
return (Pico32x.pwm_irq_cnt * pwm.cycles
cycles_diff_sh2 = sh2_now - Pico32x.pwm_cycle_p;
return (Pico32x.pwm_irq_cnt * pwm_cycles
- cycles_diff_sh2) / 3 + 1;
}
@ -170,28 +158,29 @@ void p32x_pwm_irq_event(unsigned int m68k_now)
p32x_pwm_schedule(m68k_now);
}
unsigned int p32x_pwm_read16(u32 a, SH2 *sh2, unsigned int m68k_cycles)
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/2) {
case 0/2: // control
case 2/2: // cycle
switch (a) {
case 0: // control
case 2: // cycle
d = Pico32x.regs[(0x30 + a) / 2];
break;
case 4/2: // L ch
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/2: // R ch
case 8/2: // MONO
case 6: // R ch
case 8: // MONO
if (Pico32x.pwm_p[1] == 3)
d |= P32XP_FULL;
else if (Pico32x.pwm_p[1] == 0)
@ -204,68 +193,54 @@ unsigned int p32x_pwm_read16(u32 a, SH2 *sh2, unsigned int m68k_cycles)
return d;
}
void p32x_pwm_write16(u32 a, unsigned int d, SH2 *sh2, unsigned int m68k_cycles)
void p32x_pwm_write16(unsigned int a, unsigned int d,
SH2 *sh2, unsigned int m68k_cycles)
{
unsigned short *fifo;
int idx;
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;
switch (a/2) {
case 0/2: // 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; // ?
break;
case 2/2: // cycle
Pico32x.regs[0x32 / 2] = d & 0x0fff;
p32x_pwm_ctl_changed();
break;
case 8/2: // MONO
case 6/2: // R ch
fifo = Pico32xMem->pwm_fifo[1];
idx = Pico32xMem->pwm_index[1];
if (Pico32x.pwm_p[1] < 3) {
if (Pico32x.pwm_p[1] == 2 && pwm.irq_state >= PWM_IRQ_STOPPED) {
// buffer full. If there was no buffer underrun after last fill,
// try increasing reload rate to reduce IRQs
if (pwm.irq_reload < 3 && pwm.irq_state == PWM_IRQ_HIGH)
pwm.irq_reload ++;
pwm.irq_state = PWM_IRQ_HIGH;
}
Pico32x.pwm_p[1]++;
} else {
// buffer overflow. Some roms always fill the complete buffer even if
// reload rate is set below max. Lock reload rate to programmed setting.
pwm.irq_reload = pwm.irq_timer;
pwm.irq_state = PWM_IRQ_LOCKED;
idx = (idx+1) % 4;
Pico32xMem->pwm_index[1] = idx;
}
fifo[(idx+Pico32x.pwm_p[1]) % 4] = (d - 1) & 0x0fff;
if (a != 8) break; // fallthrough if MONO
case 4/2: // L ch
fifo = Pico32xMem->pwm_fifo[0];
idx = Pico32xMem->pwm_index[0];
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 {
idx = (idx+1) % 4;
Pico32xMem->pwm_index[0] = idx;
fifo[1] = fifo[2];
fifo[2] = fifo[3];
}
fifo[(idx+Pico32x.pwm_p[0]) % 4] = (d - 1) & 0x0fff;
break;
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(s32 *buf32, int length, int stereo)
void p32x_pwm_update(int *buf32, int length, int stereo)
{
short *pwmb;
int step;
@ -277,10 +252,10 @@ void p32x_pwm_update(s32 *buf32, int length, int stereo)
xmd = Pico32x.regs[0x30 / 2] & 0x0f;
if (xmd == 0 || xmd == 0x06 || xmd == 0x09 || xmd == 0x0f)
goto out; // invalid?
if (pwm.silent)
if (pwm_silent)
return;
step = (pwm.ptr << 16) / length;
step = (pwm_ptr << 16) / length;
pwmb = Pico32xMem->pwm;
if (stereo)
@ -335,12 +310,13 @@ void p32x_pwm_update(s32 *buf32, int length, int stereo)
}
}
elprintf(EL_PWM, "pwm_update: pwm.ptr %d, len %d, step %04x, done %d",
pwm.ptr, length, step, (pwmb - Pico32xMem->pwm) / 2);
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 = pwm.current[0] == 0 && pwm.current[1] == 0;
pwm_ptr = 0;
pwm_silent = Pico32xMem->pwm_current[0] == 0
&& Pico32xMem->pwm_current[1] == 0;
}
void p32x_pwm_state_loaded(void)
@ -350,11 +326,11 @@ void p32x_pwm_state_loaded(void)
p32x_pwm_ctl_changed();
// for old savestates
cycles_diff_sh2 = Pico.t.m68c_cnt * 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 = Pico.t.m68c_cnt * 3;
p32x_pwm_schedule(Pico.t.m68c_cnt);
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);
}
}

View file

@ -1,7 +1,6 @@
/*
* SH2 peripherals/"system on chip"
* (C) notaz, 2013
* (C) irixxxx, 2019-2024
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
@ -26,14 +25,11 @@
#include "../pico_int.h"
#include "../memory.h"
#include <cpu/sh2/compiler.h>
DRC_DECLARE_SR;
// DMAC handling
struct dma_chan {
u32 sar, dar; // src, dst addr
u32 tcr; // transfer count
u32 chcr; // chan ctl
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
@ -48,11 +44,11 @@ struct dma_chan {
struct dmac {
struct dma_chan chan[2];
u32 vcrdma0;
u32 unknown0;
u32 vcrdma1;
u32 unknown1;
u32 dmaor;
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
@ -77,7 +73,7 @@ static void dmac_transfer_complete(SH2 *sh2, struct dma_chan *chan)
{
chan->chcr |= DMA_TE; // DMA has ended normally
p32x_sh2_poll_event(sh2->poll_addr, sh2, SH2_STATE_SLEEP, SekCyclesDone());
p32x_sh2_poll_event(sh2, SH2_STATE_SLEEP, SekCyclesDone());
if (chan->chcr & DMA_IE)
dmac_te_irq(sh2, chan);
}
@ -91,7 +87,6 @@ static void dmac_transfer_one(SH2 *sh2, struct dma_chan *chan)
case 0:
d = p32x_sh2_read8(chan->sar, sh2);
p32x_sh2_write8(chan->dar, d, sh2);
break;
case 1:
d = p32x_sh2_read16(chan->sar, sh2);
p32x_sh2_write16(chan->dar, d, sh2);
@ -130,25 +125,6 @@ static void dmac_transfer_one(SH2 *sh2, struct dma_chan *chan)
chan->sar += size;
}
// optimization for copying around memory with SH2 DMA
static void dmac_memcpy(struct dma_chan *chan, SH2 *sh2)
{
u32 size = (chan->chcr >> 10) & 3, up = chan->chcr & (1 << 14);
int count;
if (!up || chan->tcr < 4)
return;
if (size == 3) size = 2; // 4-word xfer mode still counts in words
// XXX check TCR being a multiple of 4 in 4-word xfer mode?
// XXX check alignment of sar/dar, generating a bus error if unaligned?
count = p32x_sh2_memcpy(chan->dar, chan->sar, chan->tcr, 1 << size, sh2);
chan->sar += count << size;
chan->dar += count << size;
chan->tcr -= count;
}
// DMA trigger by SH2 register write
static void dmac_trigger(SH2 *sh2, struct dma_chan *chan)
{
@ -158,12 +134,6 @@ static void dmac_trigger(SH2 *sh2, struct dma_chan *chan)
if (chan->chcr & DMA_AR) {
// auto-request transfer
sh2->state |= SH2_STATE_SLEEP;
if ((((chan->chcr >> 12) ^ (chan->chcr >> 14)) & 3) == 0 &&
(((chan->chcr >> 14) ^ (chan->chcr >> 15)) & 1) == 1) {
// SM == DM and either DM0 or DM1 are set. check for mem to mem copy
dmac_memcpy(chan, sh2);
}
while ((int)chan->tcr > 0)
dmac_transfer_one(sh2, chan);
dmac_transfer_complete(sh2, chan);
@ -190,9 +160,8 @@ static void dmac_trigger(SH2 *sh2, struct dma_chan *chan)
}
// timer state - FIXME
static u32 timer_cycles[2];
static u32 timer_tick_cycles[2];
static u32 timer_tick_factor[2];
static int timer_cycles[2];
static int timer_tick_cycles[2];
// timers
void p32x_timers_recalc(void)
@ -202,9 +171,6 @@ void p32x_timers_recalc(void)
// SH2 timer step
for (i = 0; i < 2; i++) {
sh2s[i].state &= ~SH2_TIMER_RUN;
if (PREG8(sh2s[i].peri_regs, 0x80) & 0x20) // TME
sh2s[i].state |= SH2_TIMER_RUN;
tmp = PREG8(sh2s[i].peri_regs, 0x80) & 7;
// Sclk cycles per timer tick
if (tmp)
@ -212,35 +178,36 @@ void p32x_timers_recalc(void)
else
cycles = 2;
timer_tick_cycles[i] = cycles;
timer_tick_factor[i] = (1ULL << 32) / cycles;
timer_cycles[i] = 0;
elprintf(EL_32XP, "WDT cycles[%d] = %d", i, cycles);
}
}
NOINLINE void p32x_timer_do(SH2 *sh2, unsigned int m68k_slice)
void p32x_timers_do(unsigned int m68k_slice)
{
unsigned int cycles = m68k_slice * 3;
void *pregs = sh2->peri_regs;
int cnt; int i = sh2->is_slave;
int cnt, i;
// WDT timer
timer_cycles[i] += cycles;
if (timer_cycles[i] > timer_tick_cycles[i]) {
// cnt = timer_cycles[i] / timer_tick_cycles[i];
cnt = (1ULL * timer_cycles[i] * timer_tick_factor[i]) >> 32;
timer_cycles[i] -= timer_tick_cycles[i] * cnt;
cnt += PREG8(pregs, 0x81);
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(sh2, level, vector);
cnt &= 0xff;
// 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;
}
PREG8(pregs, 0x81) = cnt;
}
}
@ -258,62 +225,40 @@ void sh2_peripheral_reset(SH2 *sh2)
// SH2 internal peripheral memhandlers
// we keep them in little endian format
u32 REGPARM(2) sh2_peripheral_read8(u32 a, SH2 *sh2)
u32 sh2_peripheral_read8(u32 a, SH2 *sh2)
{
u8 *r = (void *)sh2->peri_regs;
u32 d;
DRC_SAVE_SR(sh2);
a &= 0x1ff;
d = PREG8(r, a);
elprintf_sh2(sh2, EL_32XP, "peri r8 [%08x] %02x @%06x",
a | ~0x1ff, d, sh2_pc(sh2));
if ((a & 0x1c0) == 0x140) {
// abused as comm area
p32x_sh2_poll_detect(a, sh2, SH2_STATE_CPOLL, 3);
}
DRC_RESTORE_SR(sh2);
return d;
}
u32 REGPARM(2) sh2_peripheral_read16(u32 a, SH2 *sh2)
u32 sh2_peripheral_read16(u32 a, SH2 *sh2)
{
u16 *r = (void *)sh2->peri_regs;
u32 d;
DRC_SAVE_SR(sh2);
a &= 0x1fe;
d = r[MEM_BE2(a / 2)];
a &= 0x1ff;
d = r[(a / 2) ^ 1];
elprintf_sh2(sh2, EL_32XP, "peri r16 [%08x] %04x @%06x",
a | ~0x1ff, d, sh2_pc(sh2));
if ((a & 0x1c0) == 0x140) {
// abused as comm area
p32x_sh2_poll_detect(a, sh2, SH2_STATE_CPOLL, 3);
}
DRC_RESTORE_SR(sh2);
return d;
}
u32 REGPARM(2) sh2_peripheral_read32(u32 a, SH2 *sh2)
u32 sh2_peripheral_read32(u32 a, SH2 *sh2)
{
u32 d;
DRC_SAVE_SR(sh2);
a &= 0x1fc;
d = sh2->peri_regs[a / 4];
elprintf_sh2(sh2, EL_32XP, "peri r32 [%08x] %08x @%06x",
a | ~0x1ff, d, sh2_pc(sh2));
if (a == 0x18c)
// kludge for polling COMM while polling for end of DMA
sh2->poll_cnt = 0;
else if ((a & 0x1c0) == 0x140) {
// abused as comm area
p32x_sh2_poll_detect(a, sh2, SH2_STATE_CPOLL, 3);
}
DRC_RESTORE_SR(sh2);
return d;
}
@ -357,18 +302,18 @@ void REGPARM(3) sh2_peripheral_write8(u32 a, u32 d, SH2 *sh2)
u8 *r = (void *)sh2->peri_regs;
u8 old;
DRC_SAVE_SR(sh2);
elprintf_sh2(sh2, EL_32XP, "peri w8 [%08x] %02x @%06x",
a, d, sh2_pc(sh2));
a &= 0x1ff;
old = PREG8(r, a);
PREG8(r, a) = d;
switch (a) {
case 0x002: // SCR - serial control
if (!(old & 0x20) && (d & 0x20)) // TE being set
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;
@ -376,35 +321,28 @@ void REGPARM(3) sh2_peripheral_write8(u32 a, u32 d, SH2 *sh2)
d = (old & (d | 0x06)) | (d & 1);
PREG8(r, a) = d;
sci_trigger(sh2, r);
break;
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;
PREG8(r, a) = d;
break;
case 0x017: // TOCR
d |= 0xe0;
PREG8(r, a) = d;
break;
default:
if ((a & 0x1c0) == 0x140)
p32x_sh2_poll_event(a, sh2, SH2_STATE_CPOLL, SekCyclesDone());
}
DRC_RESTORE_SR(sh2);
PREG8(r, a) = d;
}
void REGPARM(3) sh2_peripheral_write16(u32 a, u32 d, SH2 *sh2)
{
u16 *r = (void *)sh2->peri_regs;
DRC_SAVE_SR(sh2);
elprintf_sh2(sh2, EL_32XP, "peri w16 [%08x] %04x @%06x",
a, d, sh2_pc(sh2));
a &= 0x1fe;
a &= 0x1ff;
// evil WDT
if (a == 0x80) {
@ -414,21 +352,17 @@ void REGPARM(3) sh2_peripheral_write16(u32 a, u32 d, SH2 *sh2)
}
if ((d & 0xff00) == 0x5a00) // WTCNT
PREG8(r, 0x81) = d;
} else {
r[MEM_BE2(a / 2)] = d;
if ((a & 0x1c0) == 0x140)
p32x_sh2_poll_event(a, sh2, SH2_STATE_CPOLL, SekCyclesDone());
return;
}
DRC_RESTORE_SR(sh2);
r[(a / 2) ^ 1] = d;
}
void REGPARM(3) sh2_peripheral_write32(u32 a, u32 d, SH2 *sh2)
{
u32 *r = sh2->peri_regs;
u32 old;
struct dmac *dmac;
DRC_SAVE_SR(sh2);
elprintf_sh2(sh2, EL_32XP, "peri w32 [%08x] %08x @%06x",
a, d, sh2_pc(sh2));
@ -436,25 +370,24 @@ void REGPARM(3) sh2_peripheral_write32(u32 a, u32 d, SH2 *sh2)
old = r[a / 4];
r[a / 4] = d;
// TODO: DRC doesn't correctly extend 'd' parameter register to 64bit :-/
switch (a) {
// division unit (TODO: verify):
case 0x104: // DVDNT: divident L, starts divide
elprintf_sh2(sh2, EL_32XP, "divide %08x / %08x",
r[0x104 / 4], r[0x100 / 4]);
d, r[0x100 / 4]);
if (r[0x100 / 4]) {
signed int divisor = r[0x100 / 4];
r[0x118 / 4] = r[0x110 / 4] = (signed int)r[0x104 / 4] % divisor;
r[0x104 / 4] = r[0x11c / 4] = r[0x114 / 4] = (signed int)r[0x104 / 4] / divisor;
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], r[0x114 / 4], r[0x100 / 4], sh2_pc(sh2));
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 | r[0x114 / 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;
@ -469,27 +402,21 @@ void REGPARM(3) sh2_peripheral_write32(u32 a, u32 d, SH2 *sh2)
else
r[0x110 / 4] = r[0x114 / 4] = r[0x118 / 4] = r[0x11c / 4] = 0; // ?
break;
// perhaps starting a DMA?
case 0x18c:
case 0x19c:
case 0x1b0:
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]);
break;
default:
if ((a & 0x1c0) == 0x140)
p32x_sh2_poll_event(a, sh2, SH2_STATE_CPOLL, SekCyclesDone());
}
DRC_RESTORE_SR(sh2);
// 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 */
@ -539,9 +466,7 @@ static void dreq1_do(SH2 *sh2, struct dma_chan *chan)
if ((chan->dar & ~0xf) != 0x20004030)
elprintf(EL_32XP|EL_ANOMALY, "dreq1: bad dar?: %08x\n", chan->dar);
sh2->state |= SH2_STATE_SLEEP;
dmac_transfer_one(sh2, chan);
sh2->state &= ~SH2_STATE_SLEEP;
if (chan->tcr == 0)
dmac_transfer_complete(sh2, chan);
}

View file

@ -49,32 +49,4 @@
#endif
// indexed branch (XB) via branch table (BT)
#ifdef __PIC__
#define PIC_XB(c,r,s) add##c pc, r, s
#define PIC_BT(a) b a
#else
#define PIC_XB(c,r,s) ldr##c pc, [pc, r, s]
#define PIC_BT(a) .word a
#endif
// load data address (LDR) either via literal pool or via GOT
#ifdef __PIC__
// can't use pool loads since ldr= only allows a symbol or a constant expr :-(
#define PIC_LDR_INIT() \
.macro pic_ldr r t a; \
ldr \r, [pc, $.LD\@-.-8]; \
ldr \t, [pc, $.LD\@-.-4]; \
.LP\@:add \r, pc; \
ldr \r, [\r, \t]; \
add pc, $4; \
.LD\@:.word _GLOBAL_OFFSET_TABLE_-.LP\@-8; \
.word \a(GOT); \
.endm;
#define PIC_LDR(r,t,a) pic_ldr r, t, a
#else
#define PIC_LDR_INIT()
#define PIC_LDR(r,t,a) ldr r, =a
#endif
#endif /* __ARM_FEATURES_H__ */

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,14 @@
# hardware (hw = ...):
# svp - Sega Virtua Processor
# pico - Sega Pico (not really cart hw, but convenient to support here)
# prot - simple copy protection devices in unlicensed cartridges (see prot. below)
# 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)
# no_z80_bus_lock - don't emulate z80 bus getting closed to the 68k when bus is released
# 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
@ -16,9 +16,6 @@
# realtec_mapper
# radica_mapper - similar to x_in_1_mapper
# piersolar_mapper - used in Pier Solar
# sf00x_mapper - versions x=1,2,4 used by superfighter team
# lk3_mapper - mapper for Lion King 3 / Super King Kong 99 and some more
# smw64_mapper - mapper for Super Mario World 64
#
# save storage memory range (inclusive, overrides ROM header):
# sram_range = <start, end>
@ -44,39 +41,14 @@ check_str = 0x150, "VIRTUA RACING"
check_str = 0x810, "OHMP"
hw = svp
[Soreike! Anpanman no Game de Asobou Anpanman - Pico]
check_str = 0x100, "SEGA IAC "
[Pico]
check_str = 0x100, "SEGA PICO"
hw = pico
# Unou Kaihatsu Series: IMA IKUNO[U]JYUKU
[Unou Kaihatsu Series - Pico]
check_str = 0x100, "IMA IKUNO"
[Pico]
check_str = 0x100, "IMA IKUNOUJYUKU"
hw = pico
# X-Men proto
[X-Men (prototype) - 32X]
check_str = 0x120, "32X SAMPLE PROGRAM"
check_str = 0x32b74c, "Bishop Level"
prop = force_6btn
# WWF Raw
[WWF Raw - 32X]
check_str = 0x100, "SEGA 32X"
check_str = 0x150, "WWF RAW"
prop = wwfraw_hack # reads back data written to high ROM adresses from cache
# Blackthorne
[Blackthorne - 32X]
check_str = 0x100, "SEGA 32X"
check_str = 0x120, "BLACKTHORNE"
prop = blackthorne_hack # reads back data overwritten by 2nd CPU from cache
# Mars check program
[Mars Check - 32X]
check_str = 0x100, "SEGA"
check_str = 0x150, "MARS CHECK PROGRAM"
prop = marscheck_hack # reads back data overwritten by DMA from cache
# sram emulation triggers some protection for this one
[Puggsy]
check_str = 0x120, "PUGGSY"
@ -91,16 +63,13 @@ prop = filled_sram
check_str = 0x150, "MICRO MACHINES II"
prop = filled_sram
# bad headers
[HardBall III]
check_str = 0x150, " HardBall III"
sram_range = 0x200000,0x20ffff
# X-Men proto
[X-Men (prototype)]
check_str = 0x150, "32X SAMPLE PROGRAM"
check_str = 0x32b74c, "Bishop Level"
prop = force_6btn
# The SSF2 mapper
[Mega Everdrive]
check_str = 0x100, "SEGA SSF"
hw = ssf2_mapper
[Super Street Fighter II - The New Challengers (U)]
check_str = 0x150, "SUPER STREET FIGHTER2 The New Challengers"
hw = ssf2_mapper
@ -112,23 +81,6 @@ check_str = 0x150, "PIER"
check_str = 0x610, "Respect"
hw = piersolar_mapper
# Beggar Prince, unusual SRAM location
[Beggar Prince]
check_str = 0x150, "BEGGAR PRINCE"
hw = sf001_mapper
sram_range = 0x400000,0x40ffff
prop = filled_sram
[Legend of Wukong]
check_str = 0x150, "LEGEND OF WUKONG"
hw = sf002_mapper
# Star Odyssey, r/w in SRAM mirror (double SRAM as a kludge)
[Star Odyssey]
check_str = 0x150, "STAR ODYSSEY"
hw = sf004_mapper
sram_range = 0x200000,0x207fff
# 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.
@ -147,16 +99,6 @@ check_str = 0x150, "ALIEN 3"
check_size_gt = 0x080000
hw = x_in_1_mapper
[5-in-1 Megadrive Portable]
check_str = 0x150, "TINY TOON ADVENTURES"
check_size_gt = 0x080000
hw = x_in_1_mapper
[40-games-in-1]
check_str = 0x160, "FS MOONWALKER"
check_size_gt = 0x080000
hw = x_in_1_mapper
[Super 15-in-1]
check_str = 0x150, " SHOVE IT!"
check_size_gt = 0x020000
@ -168,16 +110,11 @@ check_size_gt = 0x020000
hw = x_in_1_mapper
# radica
[Arcade Legends Sega]
[radica_v1]
check_str = 0x150, "KID CHAMELEON"
check_size_gt = 0x100000
hw = radica_mapper
[Arcade Legends Capcom]
check_str = 0x150, "STREET FIGHTER"
check_size_gt = 0x300000
hw = radica_mapper
# realtec
[Earth Defend, The (Unl)]
check_str = 0x94, "THE EARTH DEFEND"
@ -202,12 +139,6 @@ check_str = 0x150, "FRANK THOMAS BIGHURT BASEBAL"
eeprom_type = 3
eeprom_lines = 8,0,0
[Greatest Heavyweights]
check_str = 0x150, "GREATEST HEAVYWEIGHTS"
sram_range = 0x200000,0x200001
eeprom_type = 1
eeprom_lines = 1,0,0
[MICRO MACHINES II]
check_str = 0x150, "MICRO MACHINES II"
sram_range = 0x300000,0x380001
@ -276,224 +207,74 @@ sram_range = 0x200000,0x200001
eeprom_type = 1
eeprom_lines = 6,7,7
[Sports Talk Baseball]
check_str = 0x150, "MLBPA SPORTS TALK BASEBALL"
sram_range = 0x200000,0x200001
eeprom_type = 1
eeprom_lines = 1,0,0
# Unlicensed games with simple protections
# some of these come from Haze, some from myself (notaz).
# more added by irixxxx from Mame and G+GX
# check_crc32 calculation for 1st 64 KB only to allow for overdumps
# lk3, mapper + bitswapping hardware
[Lion King 3 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xc9706e25
hw = lk3_mapper
[Super King Kong 99 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0x4c98cc30
hw = lk3_mapper
[Gunfight 3-in-1 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0x6ec032cb
hw = lk3_mapper
[Pocket Monsters II (Unl)]
check_str = 0x104, " "
check_crc32 = 0x0d097f5c
hw = lk3_mapper
[Pokemon Stadium (Unl)]
check_str = 0x104, " "
check_crc32 = 0xbf7219df
hw = lk3_mapper
[Mulan (Unl)]
check_str = 0x104, " "
check_crc32 = 0xb5b7606e
hw = lk3_mapper
[Final Samurai V (Unl)] # aka Soul Edge
check_str = 0x104, " "
check_crc32 = 0xab3ae5e9
hw = lk3_mapper
[Top Fighter 2000 (Unl)]
check_str = 0x104, " "
check_crc32 = 0x802f53f9
hw = lk3_mapper
# smw64 mapper + prot
[Super Mario World 64 (Unl)]
check_csum = 0
check_crc32 = 0xf63b7bdc
hw = smw64_mapper
# cart I/O area
[Bug's Life, A (Unl)]
check_str = 0x104, " "
check_crc32 = 0x50aa5a9b
check_crc32 = 0x10458e09
hw = prot
prot_ro_value16 = 0xa13000,0xffff00,0x28
[Rockman X3 (Unl)]
check_csum = 0
check_crc32 = 0xee20be2c
[Elf Wor (Unl)]
check_str = 0x172, "GAME : ELF WOR"
hw = prot
prot_ro_value16 = 0xa13000,-2,0x0c
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
[Super Mario World (Unl)]
check_str = 0x104, "SEGASEGASEGA"
check_crc32 = 0xc3616596
hw = prot
prot_ro_value16 = 0xa13000,-2,0x1c
[Super Mario Bros. 2 (Unl)] # aka Super Mario 2 1998
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0x7861fb28
hw = prot
prot_ro_value16 = 0xa13000,-2,0x0a
[Pocket Monsters (Unl)]
[King of Fighters '98, The (Unl)]
check_str = 0x104, " "
check_crc32 = 0xf4cb9b37
hw = prot
prot_ro_value16 = 0xa13000,-2,0x00
prot_ro_value16 = 0xa13002,-2,0x01
prot_ro_value16 = 0xa1303e,-2,0x1f
[King of Fighters '99, The (Unl)]
check_str = 0x104, " "
check_crc32 = 0x7bdfb390
hw = prot
prot_ro_value16 = 0xa13000,-2,0x00
prot_ro_value16 = 0xa13002,-2,0x01
prot_ro_value16 = 0xa1303e,-2,0x1f
# cart upper 4MB
[King of Fighters '98+2000, The (Unl)]
check_str = 0x104, " "
check_crc32 = 0x8fb8b29e
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
[Mahjong Lover (Unl), Super Majon Club (Unl), Insane Paradise (Unl)]
# Majiang qingren, Chaoji majiang Club, Fengkuang taohuayuan (Crazy Utopia)
check_str = 0x104, " MEGA DRIVE (C)"
check_str = 0x118, "CREATON."
check_str = 0x180, "MDGM-000"
hw = prot
prot_ro_value16 = 0x400000,-2,0x9000
prot_ro_value16 = 0x401000,-2,0xd300
[Rook Mann (Unl)] # aka Rock Heaven
check_csum = 0x6cca
check_crc32 = 0xab5d5d9e
hw = prot
prot_ro_value16 = 0x500008,-2,0x5000
[Rock World (Unl)]
check_str = 0x113, "KANKO 91-92"
check_crc32 = 0x79423515
hw = prot
prot_ro_value16 = 0x500008,-2,0x5000
prot_ro_value16 = 0x500208,-2,0xa000
[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 = 0x7009cac3
check_crc32 = 0xaff46765
hw = prot
prot_rw_value16 = 0x400000,0xc00004,0
prot_rw_value16 = 0x400004,0xc00004,0
[Squirrel King (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0x1c602dd4
[Mahjong Lover (Unl)]
check_str = 0x118, "CREATON. "
check_crc32 = 0xddd02ba4
hw = prot
prot_rw_value16 = 0x400000,0xc00000,0
prot_rw_value16 = 0x400004,0xc00004,0
prot_ro_value16 = 0x400000,-2,0x9000
prot_ro_value16 = 0x401000,-2,0xd300
[Tiny Toon Adventures 3 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xc31cfcca
[Pocket Monsters (Unl)]
check_str = 0x104, " "
check_crc32 = 0xf68f6367
hw = prot
prot_rw_value16 = 0x400000,0xc00000,0
prot_rw_value16 = 0x400004,0xc00004,0
prot_ro_value16 = 0xa13002,-2,0x01
prot_ro_value16 = 0xa1303e,-2,0x1f
[Barver Battle Saga (Unl)] # Taikong zhanshi
check_csum = 0x30b9
check_crc32 = 0x35e0ff17
[Pocket Monsters (Unl) [a1]]
check_str = 0x104, " "
check_crc32 = 0xfb176667
hw = prot
prot_rw_value16 = 0x400000,0xc00000,0
prot_rw_value16 = 0x400004,0xc00004,0
prot_ro_value16 = 0xa13000,-2,0x14
prot_ro_value16 = 0xa13002,-2,0x01
prot_ro_value16 = 0xa1303e,-2,0x1f
[Final Fantasy (Unl)] # Taikong zhanshi (russian bootleg)
check_csum = 0x5ff9
check_crc32 = 0x4b2b163a
hw = prot
prot_rw_value16 = 0x400000,0xc00000,0
prot_rw_value16 = 0x400004,0xc00004,0
[Water Margin (Unl)] # Shuihu Zhuan
check_csum = 0x6001
check_crc32 = 0xfa80956a
hw = prot
prot_rw_value16 = 0x400000,0xc00000,0
prot_rw_value16 = 0x400004,0xc00004,0
[Legend of Fengshen Yingjie, The (Unl)] # Fengshen yingjie chuan (Canon)
check_csum = 0xffff
check_crc32 = 0x91865ea4
hw = prot
prot_rw_value16 = 0x400000,0xc00000,0
prot_rw_value16 = 0x400004,0xc00004,0
[Legend of Arthur, The (Unl)] # Ya se chuanshuo
check_csum = 0xffff
check_crc32 = 0x8e83dbfa
hw = prot
prot_ro_value16 = 0x400000,-2,0x6300
prot_ro_value16 = 0x400002,-2,0x9800
prot_ro_value16 = 0x400004,-2,0xc900
prot_ro_value16 = 0x400006,-2,0x1800
[Wucom Legend (Unl)] # Wukong waizhuan
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xf838aa3b
hw = prot
prot_ro_value16 = 0x400000,-2,0x6300
prot_ro_value16 = 0x400002,-2,0x9800
prot_ro_value16 = 0x400004,-2,0xc900
prot_ro_value16 = 0x400006,-2,0x1800
[Super Magician (Unl)] # Ling huan daoshi
check_str = 0x172, "GAME : ELF WOR"
hw = prot
prot_ro_value16 = 0x400000,-2,0x5500
prot_ro_value16 = 0x400002,-2,0x0f00 # check is done if the above one fails
prot_ro_value16 = 0x400004,-2,0xc900
prot_ro_value16 = 0x400006,-2,0x1800 # similar to above
[Mighty Morphin Power Rangers (Unl)]
check_str = 0x104, " "
check_crc32 = 0x5fdeb37b
hw = prot
prot_ro_value16 = 0x400000,-2,0x5500
prot_ro_value16 = 0x400002,-2,0x0f00
prot_ro_value16 = 0x400004,-2,0xc900
prot_ro_value16 = 0x400006,-2,0x1800
[Smart Mouse (Unl)] # Huanle taoqi shu
[Rockman X3 (Unl)]
check_csum = 0
check_crc32 = 0xc9539fce
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
@ -502,74 +283,38 @@ prot_ro_value16 = 0x400006,-2,0xf000
[Soul Blade (Unl)]
check_str = 0x104, " "
check_crc32 = 0x6a95f766
check_crc32 = 0xf26f88d1
hw = prot
prot_ro_value16 = 0x400000,-2,0x6300
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 = 0xf93f3d0b
check_crc32 = 0x4820a161
hw = prot
prot_ro_value16 = 0x400000,-2,0x5500
prot_ro_value16 = 0x400002,-2,0x0f00
[Battle of Red Cliffs, The (Unl)] # Sanguo yanyi (Romance of the 3 Kingdoms)
[Super King Kong 99 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0x66165305
check_crc32 = 0x413dfee2
hw = prot_lk3
[Super Mario Bros. (Unl)]
check_str = 0x140, "SUPER MARIO BROS "
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
prot_ro_value16 = 0xa13000,-2,0x0c
[Tunderbolt II (Unl)] # Leidian
check_str = 0xfe, "WISEGAME"
check_crc32 = 0x6f01bd65
[Super Mario 2 1998 (Unl)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xf7e1b3e1
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
prot_ro_value16 = 0xa13000,-2,0x0a
[16 Tiles Mahjong 1+2 (Unl)] # Zhang majiang
check_str = 0xfe, "WISEGAME IS TRADE MARKER"
[Squirrel King (R)]
check_str = 0x104, " are Registered Trademarks"
check_crc32 = 0xb8261ff5
hw = prot
prot_ro_value16 = 0x400002,-2,0xaa00
prot_ro_value16 = 0x400004,-2,0xc900
prot_ro_value16 = 0x400006,-2,0xf000
prot_rw_value16 = 0x400000,0xc00000,0
[Super Poker (Unl)] # Chaoji puke
check_csum = 0xffff
check_crc32 = 0xdd02797c
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
[777 Casino (Unl)] # Menghuan shuiguo pan
check_csum = 0
check_crc32 = 0xee9fc429
hw = prot
prot_ro_value16 = 0x400000,-2,0x6300
# Unlicensed homebrew games made by V.M.V.
# to prevent bus conflicts between the audio drivers in 68k and Z80
[Ben 10 (Unl)]
check_str = 0x180, "GM 00000000-00"
check_crc32 = 0x6732aab4
prop = no_z80_bus_lock
[Mario 3: Vokrug Sveta (Unl)]
check_str = 0x180, "GM 00000000-00"
check_crc32 = 0xe302585a
prop = no_z80_bus_lock
[Mario 4: Kosmicheskaya Odisseya (Unl)]
check_csum = 8224
check_crc32 = 0x20ed0de8
prop = no_z80_bus_lock

View file

@ -1,7 +1,6 @@
/*
* Support for a few cart mappers and some protection.
* (C) notaz, 2008-2011
* (C) irixxxx, 2021-2022
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
@ -9,98 +8,67 @@
#include "../pico_int.h"
#include "../memory.h"
#include "eeprom_spi.h"
static int have_bank(u32 base)
{
// the loader allocs in 512K quantities
if (base >= Pico.romsize) {
elprintf(EL_ANOMALY|EL_STATUS, "carthw: missing bank @ %06x", base);
return 0;
}
return 1;
}
/* standard/ssf2 mapper */
int carthw_ssf2_active;
unsigned char carthw_ssf2_banks[8];
/* The SSFII mapper */
static unsigned char ssf2_banks[8];
static carthw_state_chunk carthw_ssf2_state[] =
{
{ CHUNK_CARTHW, sizeof(carthw_ssf2_banks), &carthw_ssf2_banks },
{ 0, 0, NULL }
{ CHUNK_CARTHW, sizeof(ssf2_banks), &ssf2_banks },
{ 0, 0, NULL }
};
void carthw_ssf2_write8(u32 a, u32 d)
static void carthw_ssf2_write8(u32 a, u32 d)
{
u32 target, base;
u32 target, base;
if ((a & ~0x0e) != 0xa130f1 || a == 0xa130f1) {
PicoWrite8_io(a, d);
return;
}
if ((a & 0xfffff0) != 0xa130f0) {
PicoWrite8_io(a, d);
return;
}
a &= 0x0e;
if (a == 0)
return;
if (carthw_ssf2_banks[a >> 1] == d)
return;
a &= 0x0e;
if (a == 0)
return;
base = d << 19;
target = a << 18;
if (!have_bank(base))
return;
carthw_ssf2_banks[a >> 1] = d;
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);
}
void carthw_ssf2_write16(u32 a, u32 d)
{
PicoWrite16_io(a, d);
if ((a & ~0x0f) == 0xa130f0)
carthw_ssf2_write8(a + 1, d);
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);
cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, carthw_ssf2_write16, 1);
cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_ssf2_write8, 1);
}
static void carthw_ssf2_statef(void)
{
int i, reg;
for (i = 1; i < 8; i++) {
reg = carthw_ssf2_banks[i];
carthw_ssf2_banks[i] = i;
carthw_ssf2_write8(0xa130f1 | (i << 1), reg);
}
}
static void carthw_ssf2_unload(void)
{
memset(carthw_ssf2_banks, 0, sizeof(carthw_ssf2_banks));
carthw_ssf2_active = 0;
int i;
for (i = 1; i < 8; i++)
carthw_ssf2_write8(0xa130f0 | (i << 1), ssf2_banks[i]);
}
void carthw_ssf2_startup(void)
{
int i;
int i;
elprintf(EL_STATUS, "SSF2 mapper startup");
elprintf(EL_STATUS, "SSF2 mapper startup");
// default map
for (i = 0; i < 8; i++)
carthw_ssf2_banks[i] = i;
// default map
for (i = 0; i < 8; i++)
ssf2_banks[i] = i;
PicoCartMemSetup = carthw_ssf2_mem_setup;
PicoLoadStateHook = carthw_ssf2_statef;
PicoCartUnloadHook = carthw_ssf2_unload;
carthw_chunks = carthw_ssf2_state;
carthw_ssf2_active = 1;
PicoCartMemSetup = carthw_ssf2_mem_setup;
PicoLoadStateHook = carthw_ssf2_statef;
carthw_chunks = carthw_ssf2_state;
}
@ -134,7 +102,7 @@ static carthw_state_chunk carthw_Xin1_state[] =
{ 0, 0, NULL }
};
// TODO: reads should also work, but then we need to handle open bus
// TODO: test a0, reads, w16
static void carthw_Xin1_write8(u32 a, u32 d)
{
if ((a & 0xffff00) != 0xa13000) {
@ -142,23 +110,12 @@ static void carthw_Xin1_write8(u32 a, u32 d)
return;
}
carthw_Xin1_do(a, 0x3e, 16);
}
static void carthw_Xin1_write16(u32 a, u32 d)
{
if ((a & 0xffff00) != 0xa13000) {
PicoWrite16_io(a, d);
return;
}
carthw_Xin1_write8(a + 1, d);
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);
cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, carthw_Xin1_write16, 1);
cpu68k_map_set(m68k_write8_map, 0xa10000, 0xa1ffff, carthw_Xin1_write8, 1);
}
static void carthw_Xin1_reset(void)
@ -313,7 +270,6 @@ static carthw_state_chunk carthw_pier_state[] =
{
{ CHUNK_CARTHW, sizeof(pier_regs), pier_regs },
{ CHUNK_CARTHW + 1, sizeof(pier_dump_prot), &pier_dump_prot },
{ CHUNK_CARTHW + 2, 0, NULL }, // filled later
{ 0, 0, NULL }
};
@ -352,8 +308,7 @@ static void carthw_pier_write8(u32 a, u32 d)
base = d << 19;
goto do_map;
case 0x09:
Pico.sv.changed = 1;
eeprom_spi_write(d);
// TODO
break;
case 0x0b:
// eeprom read
@ -366,9 +321,10 @@ static void carthw_pier_write8(u32 a, u32 d)
return;
do_map:
if (!have_bank(base))
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);
}
@ -390,7 +346,7 @@ static u32 carthw_pier_read8(u32 a)
return PicoRead8_io(a);
if (a == 0xa1300b)
return eeprom_spi_read(a);
return 0; // TODO
elprintf(EL_UIO, "pier r8 [%06x] @%06x", a, SekPc);
return 0;
@ -410,7 +366,7 @@ static u32 carthw_pier_prot_read8(u32 a)
}
elprintf(EL_UIO, "pier r8 [%06x] @%06x", a, SekPc);
return Pico.rom[MEM_BE2(a & 0x7fff)];
return Pico.rom[(a & 0x7fff) ^ 1];
}
static void carthw_pier_mem_setup(void)
@ -457,14 +413,12 @@ 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();
eeprom_spi_init(NULL);
}
void carthw_pier_startup(void)
{
void *eeprom_state;
int eeprom_size = 0;
int i;
elprintf(EL_STATUS, "Pier Solar mapper startup");
@ -476,282 +430,26 @@ void carthw_pier_startup(void)
return;
}
pier_dump_prot = 3;
// create dump protection bank
for (i = 0; i < M68K_BANK_SIZE; i += 0x8000)
memcpy(Pico.rom + Pico.romsize + i, Pico.rom, 0x8000);
// save EEPROM
eeprom_state = eeprom_spi_init(&eeprom_size);
Pico.sv.flags = 0;
Pico.sv.size = 0x10000;
Pico.sv.data = calloc(1, Pico.sv.size);
if (!Pico.sv.data)
Pico.sv.size = 0;
carthw_pier_state[2].ptr = eeprom_state;
carthw_pier_state[2].size = eeprom_size;
PicoCartMemSetup = carthw_pier_mem_setup;
PicoResetHook = carthw_pier_reset;
PicoLoadStateHook = carthw_pier_statef;
carthw_chunks = carthw_pier_state;
}
/* superfighter mappers, see mame: mame/src/devices/bus/megadrive/rom.cpp */
unsigned int carthw_sf00x_reg;
static carthw_state_chunk carthw_sf00x_state[] =
{
{ CHUNK_CARTHW, sizeof(carthw_sf00x_reg), &carthw_sf00x_reg },
{ 0, 0, NULL }
};
// SF-001
// additionally map SRAM at 0x3c0000 for the newer version of sf001
static u32 carthw_sf001_read8_sram(u32 a)
{
return m68k_read8((a & 0xffff) + Pico.sv.start);
}
static u32 carthw_sf001_read16_sram(u32 a)
{
return m68k_read16((a & 0xffff) + Pico.sv.start);
}
static void carthw_sf001_write8_sram(u32 a, u32 d)
{
m68k_write8((a & 0xffff) + Pico.sv.start, d);
}
static void carthw_sf001_write16_sram(u32 a, u32 d)
{
m68k_write16((a & 0xffff) + Pico.sv.start, d);
}
static void carthw_sf001_write8(u32 a, u32 d)
{
if ((a & 0xf00) != 0xe00 || (carthw_sf00x_reg & 0x20)) // wrong addr / locked
return;
if (d & 0x80) {
// bank 0xe at addr 0x000000
cpu68k_map_set(m68k_read8_map, 0x000000, 0x040000-1, Pico.rom+0x380000, 0);
cpu68k_map_set(m68k_read16_map, 0x000000, 0x040000-1, Pico.rom+0x380000, 0);
// SRAM also at 0x3c0000 for newer mapper version
cpu68k_map_set(m68k_read8_map, 0x3c0000, 0x400000-1, carthw_sf001_read8_sram, 1);
cpu68k_map_set(m68k_read16_map, 0x3c0000, 0x400000-1, carthw_sf001_read16_sram, 1);
cpu68k_map_set(m68k_write8_map, 0x3c0000, 0x400000-1, carthw_sf001_write8_sram, 1);
cpu68k_map_set(m68k_write16_map,0x3c0000, 0x400000-1, carthw_sf001_write16_sram, 1);
} else {
// bank 0x0 at addr 0x000000
cpu68k_map_set(m68k_read8_map, 0x000000, 0x040000-1, Pico.rom, 0);
cpu68k_map_set(m68k_read16_map, 0x000000, 0x040000-1, Pico.rom, 0);
// SRAM off, bank 0xf at addr 0x3c0000
cpu68k_map_set(m68k_read8_map, 0x3c0000, 0x400000-1, Pico.rom+0x3c0000, 0);
cpu68k_map_set(m68k_read16_map, 0x3c0000, 0x400000-1, Pico.rom+0x3c0000, 0);
cpu68k_map_set(m68k_write8_map, 0x3c0000, 0x400000-1, Pico.rom+0x3c0000, 0);
cpu68k_map_set(m68k_write16_map,0x3c0000, 0x400000-1, Pico.rom+0x3c0000, 0);
}
carthw_sf00x_reg = d;
}
static void carthw_sf001_write16(u32 a, u32 d)
{
carthw_sf001_write8(a + 1, d);
}
static void carthw_sf001_mem_setup(void)
{
// writing to low cartridge addresses
cpu68k_map_set(m68k_write8_map, 0x000000, 0x00ffff, carthw_sf001_write8, 1);
cpu68k_map_set(m68k_write16_map, 0x000000, 0x00ffff, carthw_sf001_write16, 1);
}
static void carthw_sf001_reset(void)
{
carthw_sf00x_reg = 0;
carthw_sf001_write8(0x0e01, 0);
}
static void carthw_sf001_statef(void)
{
int reg = carthw_sf00x_reg;
carthw_sf00x_reg = 0;
carthw_sf001_write8(0x0e01, reg);
}
void carthw_sf001_startup(void)
{
PicoCartMemSetup = carthw_sf001_mem_setup;
PicoResetHook = carthw_sf001_reset;
PicoLoadStateHook = carthw_sf001_statef;
carthw_chunks = carthw_sf00x_state;
}
// SF-002
static void carthw_sf002_write8(u32 a, u32 d)
{
if ((a & 0xf00) != 0xe00)
return;
if (d & 0x80) {
// bank 0x00-0x0e on addr 0x20000
cpu68k_map_set(m68k_read8_map, 0x200000, 0x3c0000-1, Pico.rom, 0);
cpu68k_map_set(m68k_read16_map, 0x200000, 0x3c0000-1, Pico.rom, 0);
} else {
// bank 0x10-0x1e on addr 0x20000
cpu68k_map_set(m68k_read8_map, 0x200000, 0x3c0000-1, Pico.rom+0x200000, 0);
cpu68k_map_set(m68k_read16_map, 0x200000, 0x3c0000-1, Pico.rom+0x200000, 0);
}
carthw_sf00x_reg = d;
}
static void carthw_sf002_write16(u32 a, u32 d)
{
carthw_sf002_write8(a + 1, d);
}
static void carthw_sf002_mem_setup(void)
{
// writing to low cartridge addresses
cpu68k_map_set(m68k_write8_map, 0x000000, 0x00ffff, carthw_sf002_write8, 1);
cpu68k_map_set(m68k_write16_map, 0x000000, 0x00ffff, carthw_sf002_write16, 1);
}
static void carthw_sf002_reset(void)
{
carthw_sf002_write8(0x0e01, 0);
}
static void carthw_sf002_statef(void)
{
carthw_sf002_write8(0x0e01, carthw_sf00x_reg);
}
void carthw_sf002_startup(void)
{
PicoCartMemSetup = carthw_sf002_mem_setup;
PicoResetHook = carthw_sf002_reset;
PicoLoadStateHook = carthw_sf002_statef;
carthw_chunks = carthw_sf00x_state;
}
// SF-004
// reading from cartridge I/O region returns the current bank index
static u32 carthw_sf004_read8(u32 a)
{
if ((a & ~0xff) == 0xa13000)
return carthw_sf00x_reg & 0xf0; // bank index
return PicoRead8_io(a);
}
static u32 carthw_sf004_read16(u32 a)
{
if ((a & ~0xff) == 0xa13000)
return carthw_sf00x_reg & 0xf0;
return PicoRead16_io(a);
}
// writing to low cartridge adresses changes mappings
static void carthw_sf004_write8(u32 a, u32 d)
{
int idx, i;
unsigned bs = 0x40000; // bank size
// there are 3 byte-sized regs, stored together in carthw_sf00x_reg
if (!(carthw_sf00x_reg & 0x8000))
return; // locked
switch (a & 0xf00) {
case 0xd00:
carthw_sf00x_reg = (carthw_sf00x_reg & ~0xff0000) | ((d & 0xff) << 16);
return PicoWrite8_io(0xa130f1, (d & 0x80) ? SRR_MAPPED : 0); // SRAM mapping
case 0xe00:
carthw_sf00x_reg = (carthw_sf00x_reg & ~0x00ff00) | ((d & 0xff) << 8);
break;
case 0xf00:
carthw_sf00x_reg = (carthw_sf00x_reg & ~0x0000ff) | ((d & 0xff) << 0);
break;
default:
return; // wrong addr
}
// bank mapping changed
idx = ((carthw_sf00x_reg>>4) & 0x7); // bank index
if ((carthw_sf00x_reg>>8) & 0x40) {
// linear bank mapping, starting at idx
for (i = 0; i < 8; i++, idx = (idx+1) & 0x7) {
cpu68k_map_set(m68k_read8_map, i*bs, (i+1)*bs-1, Pico.rom + idx*bs, 0);
cpu68k_map_set(m68k_read16_map, i*bs, (i+1)*bs-1, Pico.rom + idx*bs, 0);
}
} else {
// single bank mapping
for (i = 0; i < 8; i++) {
cpu68k_map_set(m68k_read8_map, i*bs, (i+1)*bs-1, Pico.rom + idx*bs, 0);
cpu68k_map_set(m68k_read16_map, i*bs, (i+1)*bs-1, Pico.rom + idx*bs, 0);
}
}
}
static void carthw_sf004_write16(u32 a, u32 d)
{
carthw_sf004_write8(a + 1, d);
}
static void carthw_sf004_mem_setup(void)
{
// writing to low cartridge addresses
cpu68k_map_set(m68k_write8_map, 0x000000, 0x00ffff, carthw_sf004_write8, 1);
cpu68k_map_set(m68k_write16_map, 0x000000, 0x00ffff, carthw_sf004_write16, 1);
// reading from the cartridge I/O region
cpu68k_map_set(m68k_read8_map, 0xa10000, 0xa1ffff, carthw_sf004_read8, 1);
cpu68k_map_set(m68k_read16_map, 0xa10000, 0xa1ffff, carthw_sf004_read16, 1);
}
static void carthw_sf004_reset(void)
{
carthw_sf00x_reg = -1;
carthw_sf004_write8(0x0d01, 0);
carthw_sf004_write8(0x0f01, 0);
carthw_sf004_write8(0x0e01, 0x80);
}
static void carthw_sf004_statef(void)
{
int reg = carthw_sf00x_reg;
carthw_sf00x_reg = -1;
carthw_sf004_write8(0x0d01, reg >> 16);
carthw_sf004_write8(0x0f01, reg >> 0);
carthw_sf004_write8(0x0e01, reg >> 8);
}
void carthw_sf004_startup(void)
{
PicoCartMemSetup = carthw_sf004_mem_setup;
PicoResetHook = carthw_sf004_reset;
PicoLoadStateHook = carthw_sf004_statef;
carthw_chunks = carthw_sf00x_state;
}
/* Simple unlicensed ROM protection emulation */
static struct {
u32 addr;
u32 mask;
u16 val;
u16 readonly;
} sprot_items[8];
} *sprot_items;
static int sprot_item_alloc;
static int sprot_item_count;
static carthw_state_chunk carthw_sprot_state[] =
{
{ CHUNK_CARTHW, sizeof(sprot_items), &sprot_items },
{ 0, 0, NULL }
};
static u16 *carthw_sprot_get_val(u32 a, int rw_only)
{
int i;
@ -769,6 +467,9 @@ 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;
@ -777,33 +478,39 @@ static u32 PicoRead8_sprot(u32 a)
elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc);
return d;
}
else if (0xa10000 <= a && a <= 0xa1ffff)
return PicoRead8_io(a);
elprintf(EL_UIO, "prot r8 [%06x] MISS @%06x", a, SekPc);
return 0;
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 if (0xa10000 <= a && a <= 0xa1ffff)
return PicoRead16_io(a);
elprintf(EL_UIO, "prot r16 [%06x] MISS @%06x", a, SekPc);
return 0;
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)
@ -812,33 +519,45 @@ static void PicoWrite8_sprot(u32 a, u32 d)
*val = (*val & 0x00ff) | (d << 8);
elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
}
else if (0xa10000 <= a && a <= 0xa1ffff)
return PicoWrite8_io(a, d);
elprintf(EL_UIO, "prot w8 [%06x] %02x MISS @%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 if (0xa10000 <= a && a <= 0xa1ffff)
return PicoWrite16_io(a, d);
elprintf(EL_UIO, "prot w16 [%06x] %04x MISS @%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)
{
int sprot_elems = sizeof(sprot_items)/sizeof(sprot_items[0]);
if (sprot_item_count == sprot_elems) {
elprintf(EL_STATUS, "too many sprot items");
return;
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;
@ -850,17 +569,17 @@ void carthw_sprot_new_location(unsigned int a, unsigned int mask, unsigned short
static void carthw_sprot_unload(void)
{
sprot_item_count = 0;
free(sprot_items);
sprot_items = NULL;
sprot_item_count = sprot_item_alloc = 0;
}
static void carthw_sprot_mem_setup(void)
{
int start;
// map 0x400000 - 0x7fffff, /TIME areas (which are tipically used)
// map ROM - 0x7fffff, /TIME areas (which are tipically used)
start = (Pico.romsize + M68K_BANK_MASK) & ~M68K_BANK_MASK;
if (start < 0x400000) start = 0x400000;
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);
@ -878,41 +597,32 @@ void carthw_sprot_startup(void)
PicoCartMemSetup = carthw_sprot_mem_setup;
PicoCartUnloadHook = carthw_sprot_unload;
carthw_chunks = carthw_sprot_state;
}
/* Protection emulation for Lion King 3. Credits go to Haze */
static struct {
u32 bank;
u8 cmd, data;
} carthw_lk3_regs;
static carthw_state_chunk carthw_lk3_state[] =
{
{ CHUNK_CARTHW, sizeof(carthw_lk3_regs), &carthw_lk3_regs },
{ 0, 0, NULL }
};
static u8 *carthw_lk3_mem; // shadow copy memory
static u32 carthw_lk3_madr[0x100000/M68K_BANK_SIZE];
static u8 prot_lk3_cmd, prot_lk3_data;
static u32 PicoRead8_plk3(u32 a)
{
u32 d = 0;
switch (carthw_lk3_regs.cmd) {
case 0: d = carthw_lk3_regs.data << 1; break;
case 1: d = carthw_lk3_regs.data >> 1; break;
switch (prot_lk3_cmd) {
case 1: d = prot_lk3_data >> 1; break;
case 2: // nibble rotate
d = ((carthw_lk3_regs.data >> 4) | (carthw_lk3_regs.data << 4)) & 0xff;
d = ((prot_lk3_data >> 4) | (prot_lk3_data << 4)) & 0xff;
break;
case 3: // bit rotate
d = carthw_lk3_regs.data;
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", carthw_lk3_regs.cmd, SekPc);
elprintf(EL_UIO, "unhandled prot cmd %02x @%06x", prot_lk3_cmd, SekPc);
break;
}
@ -924,207 +634,48 @@ static void PicoWrite8_plk3p(u32 a, u32 d)
{
elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
if (a & 2)
carthw_lk3_regs.cmd = d & 0x3;
prot_lk3_cmd = d;
else
carthw_lk3_regs.data = d;
prot_lk3_data = d;
}
static void PicoWrite8_plk3b(u32 a, u32 d)
{
u32 addr;
int addr;
elprintf(EL_UIO, "prot w8 [%06x] %02x @%06x", a, d & 0xff, SekPc);
addr = d << 15;
if (addr+0x10000 >= Pico.romsize) {
elprintf(EL_UIO|EL_ANOMALY, "lk3_mapper: bank too large: %02x", d);
if (addr + 0x8000 > Pico.romsize) {
elprintf(EL_UIO|EL_ANOMALY, "prot_lk3: bank too large: %02x", d);
return;
}
if (addr != carthw_lk3_regs.bank) {
// banking is by or'ing the bank address in the 1st megabyte, not adding.
// only do linear mapping if map addresses aren't overlapping bank address
u32 len = M68K_BANK_SIZE;
u32 a, b;
for (b = 0x000000; b < 0x0100000; b += len) {
if (!((b + (len-1)) & addr)) {
cpu68k_map_set(m68k_read8_map, b, b + (len-1), Pico.rom+addr + b, 0);
cpu68k_map_set(m68k_read16_map, b, b + (len-1), Pico.rom+addr + b, 0);
} else {
// overlap. ugh, need a shadow copy since banks can contain code and
// 68K cpu emulator cores need mapped access to code memory
if (carthw_lk3_madr[b/len] != addr) // only if shadow isn't the same
for (a = b; a < b+M68K_BANK_SIZE; a += 0x8000)
memcpy(carthw_lk3_mem + a, Pico.rom + (addr|a), 0x8000);
carthw_lk3_madr[b/len] = addr;
cpu68k_map_set(m68k_read8_map, b, b + (len-1), carthw_lk3_mem + b, 0);
cpu68k_map_set(m68k_read16_map, b, b + (len-1), carthw_lk3_mem + b, 0);
}
}
}
carthw_lk3_regs.bank = addr;
if (addr == 0)
memcpy(Pico.rom, Pico.rom + Pico.romsize, 0x8000);
else
memcpy(Pico.rom, Pico.rom + addr, 0x8000);
}
static void carthw_lk3_mem_setup(void)
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);
carthw_lk3_regs.bank = 0;
}
static void carthw_lk3_statef(void)
void carthw_prot_lk3_startup(void)
{
PicoWrite8_plk3b(0x700000, carthw_lk3_regs.bank >> 15);
}
int ret;
static void carthw_lk3_unload(void)
{
free(carthw_lk3_mem);
carthw_lk3_mem = NULL;
memset(carthw_lk3_madr, 0, sizeof(carthw_lk3_madr));
}
void carthw_lk3_startup(void)
{
elprintf(EL_STATUS, "lk3 prot emu startup");
// allocate space for shadow copy
if (carthw_lk3_mem == NULL)
carthw_lk3_mem = malloc(0x100000);
if (carthw_lk3_mem == NULL) {
// 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_lk3_mem_setup;
PicoLoadStateHook = carthw_lk3_statef;
PicoCartUnloadHook = carthw_lk3_unload;
carthw_chunks = carthw_lk3_state;
PicoCartMemSetup = carthw_prot_lk3_mem_setup;
}
/* SMW64 mapper, based on mame source */
static struct {
u32 bank60, bank61;
u16 data[8], ctrl[4];
} carthw_smw64_regs;
static carthw_state_chunk carthw_smw64_state[] =
{
{ CHUNK_CARTHW, sizeof(carthw_smw64_regs), &carthw_smw64_regs },
{ 0, 0, NULL }
};
static u32 PicoRead8_smw64(u32 a)
{
u16 *data = carthw_smw64_regs.data, *ctrl = carthw_smw64_regs.ctrl;
u32 d = 0;
if (a & 1) {
if (a>>16 == 0x66) switch ((a>>1) & 7) {
case 0: d = carthw_smw64_regs.data[0] ; break;
case 1: d = carthw_smw64_regs.data[0]+1; break;
case 2: d = carthw_smw64_regs.data[1] ; break;
case 3: d = carthw_smw64_regs.data[1]+1; break;
case 4: d = carthw_smw64_regs.data[2] ; break;
case 5: d = carthw_smw64_regs.data[2]+1; break;
case 6: d = carthw_smw64_regs.data[2]+2; break;
case 7: d = carthw_smw64_regs.data[2]+3; break;
} else /*0x67*/ { // :-O
if (ctrl[1] & 0x80)
d = ctrl[2] & 0x40 ? data[4]&data[5] : data[4]^0xff;
if (a & 2)
d &= 0x7f;
else if (ctrl[2] & 0x80) {
if (ctrl[2] & 0x20)
data[2] = (data[5] << 2) & 0xfc;
else
data[0] = ((data[4] << 1) ^ data[3]) & 0xfe;
}
}
}
elprintf(EL_UIO, "prot r8 [%06x] %02x @%06x", a, d, SekPc);
return d;
}
static u32 PicoRead16_smw64(u32 a)
{
return PicoRead8_smw64(a+1);
}
static void PicoWrite8_smw64(u32 a, u32 d)
{
u16 *data = carthw_smw64_regs.data, *ctrl = carthw_smw64_regs.ctrl;
if ((a & 3) == 1) {
switch (a >> 16) {
case 0x60: ctrl[0] = d; break;
case 0x64: data[4] = d; break;
case 0x67:
if (ctrl[1] & 0x80) {
carthw_smw64_regs.bank60 = 0x80000 + ((d<<14) & 0x70000);
cpu68k_map_set(m68k_read8_map, 0x600000, 0x60ffff, Pico.rom + carthw_smw64_regs.bank60, 0);
cpu68k_map_set(m68k_read16_map, 0x600000, 0x60ffff, Pico.rom + carthw_smw64_regs.bank60, 0);
}
ctrl[2] = d;
}
} else if ((a & 3) == 3) {
switch (a >> 16) {
case 0x61: ctrl[1] = d; break;
case 0x64: data[5] = d; break;
case 0x60:
switch (ctrl[0] & 7) { // :-O
case 0: data[0] = (data[0]^data[3] ^ d) & 0xfe; break;
case 1: data[1] = ( d) & 0xfe; break;
case 7:
carthw_smw64_regs.bank61 = 0x80000 + ((d<<14) & 0x70000);
cpu68k_map_set(m68k_read8_map, 0x610000, 0x61ffff, Pico.rom + carthw_smw64_regs.bank61, 0);
cpu68k_map_set(m68k_read16_map, 0x610000, 0x61ffff, Pico.rom + carthw_smw64_regs.bank61, 0);
break;
}
data[3] = d;
}
}
}
static void PicoWrite16_smw64(u32 a, u32 d)
{
PicoWrite8_smw64(a+1, d);
}
static void carthw_smw64_mem_setup(void)
{
// 1st 512 KB mirrored
cpu68k_map_set(m68k_read8_map, 0x080000, 0x0fffff, Pico.rom, 0);
cpu68k_map_set(m68k_read16_map, 0x080000, 0x0fffff, Pico.rom, 0);
cpu68k_map_set(m68k_read8_map, 0x660000, 0x67ffff, PicoRead8_smw64, 1);
cpu68k_map_set(m68k_read16_map, 0x660000, 0x67ffff, PicoRead16_smw64, 1);
cpu68k_map_set(m68k_write8_map, 0x600000, 0x67ffff, PicoWrite8_smw64, 1);
cpu68k_map_set(m68k_write16_map, 0x600000, 0x67ffff, PicoWrite16_smw64, 1);
}
static void carthw_smw64_statef(void)
{
cpu68k_map_set(m68k_read8_map, 0x600000, 0x60ffff, Pico.rom + carthw_smw64_regs.bank60, 0);
cpu68k_map_set(m68k_read16_map, 0x600000, 0x60ffff, Pico.rom + carthw_smw64_regs.bank60, 0);
cpu68k_map_set(m68k_read8_map, 0x610000, 0x61ffff, Pico.rom + carthw_smw64_regs.bank61, 0);
cpu68k_map_set(m68k_read16_map, 0x610000, 0x61ffff, Pico.rom + carthw_smw64_regs.bank61, 0);
}
static void carthw_smw64_reset(void)
{
memset(&carthw_smw64_regs, 0, sizeof(carthw_smw64_regs));
}
void carthw_smw64_startup(void)
{
elprintf(EL_STATUS, "SMW64 mapper startup");
PicoCartMemSetup = carthw_smw64_mem_setup;
PicoResetHook = carthw_smw64_reset;
PicoLoadStateHook = carthw_smw64_statef;
carthw_chunks = carthw_smw64_state;
}
// vim:ts=2:sw=2:expandtab

View file

@ -1,6 +1,5 @@
/* svp */
#include "../pico_types.h"
#include "svp/ssp16.h"
typedef struct {
@ -15,24 +14,15 @@ void PicoSVPInit(void);
void PicoSVPStartup(void);
void PicoSVPMemSetup(void);
/* standard/ssf2 mapper */
extern int carthw_ssf2_active;
extern unsigned char carthw_ssf2_banks[8];
void carthw_ssf2_startup(void);
void carthw_ssf2_write8(u32 a, u32 d);
/* 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_sf001_startup(void);
void carthw_sf002_startup(void);
void carthw_sf004_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_lk3_startup(void);
void carthw_smw64_startup(void);
void carthw_prot_lk3_startup(void);

View file

@ -1,360 +0,0 @@
/****************************************************************************
* Genesis Plus
* SPI Serial EEPROM (25xxx/95xxx) support
*
* 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 "../cd/genplus_macros.h"
#include "eeprom_spi.h"
/* max supported size 64KB (25x512/95x512) */
#define SIZE_MASK 0xffff
#define PAGE_MASK 0x7f
/* hard-coded board implementation (!WP pin not used) */
#define BIT_DATA (0)
#define BIT_CLK (1)
#define BIT_HOLD (2)
#define BIT_CS (3)
typedef enum
{
STANDBY,
GET_OPCODE,
GET_ADDRESS,
WRITE_BYTE,
READ_BYTE
} T_STATE_SPI;
typedef struct
{
uint8 cs; /* !CS line state */
uint8 clk; /* SCLK line state */
uint8 out; /* SO line state */
uint8 status; /* status register */
uint8 opcode; /* 8-bit opcode */
uint8 buffer; /* 8-bit data buffer */
uint16 addr; /* 16-bit address */
uint32 cycles; /* current operation cycle */
T_STATE_SPI state; /* current operation state */
} T_EEPROM_SPI;
static T_EEPROM_SPI spi_eeprom;
void *eeprom_spi_init(int *size)
{
/* reset eeprom state */
memset(&spi_eeprom, 0, sizeof(T_EEPROM_SPI));
spi_eeprom.out = 1;
spi_eeprom.state = GET_OPCODE;
if (size)
*size = sizeof(T_EEPROM_SPI);
return &spi_eeprom;
}
void eeprom_spi_write(unsigned char data)
{
/* Make sure !HOLD is high */
if (data & (1 << BIT_HOLD))
{
/* Check !CS state */
if (data & (1 << BIT_CS))
{
/* !CS high -> end of current operation */
spi_eeprom.cycles = 0;
spi_eeprom.out = 1;
spi_eeprom.opcode = 0;
spi_eeprom.state = GET_OPCODE;
}
else
{
/* !CS low -> process current operation */
switch (spi_eeprom.state)
{
case GET_OPCODE:
{
/* latch data on CLK positive edge */
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
{
/* 8-bit opcode buffer */
spi_eeprom.opcode |= ((data >> BIT_DATA) & 1);
spi_eeprom.cycles++;
/* last bit ? */
if (spi_eeprom.cycles == 8)
{
/* reset cycles count */
spi_eeprom.cycles = 0;
/* Decode instruction */
switch (spi_eeprom.opcode)
{
case 0x01:
{
/* WRITE STATUS */
spi_eeprom.buffer = 0;
spi_eeprom.state = WRITE_BYTE;
break;
}
case 0x02:
{
/* WRITE BYTE */
spi_eeprom.addr = 0;
spi_eeprom.state = GET_ADDRESS;
break;
}
case 0x03:
{
/* READ BYTE */
spi_eeprom.addr = 0;
spi_eeprom.state = GET_ADDRESS;
break;
}
case 0x04:
{
/* WRITE DISABLE */
spi_eeprom.status &= ~0x02;
spi_eeprom.state = STANDBY;
break;
}
case 0x05:
{
/* READ STATUS */
spi_eeprom.buffer = spi_eeprom.status;
spi_eeprom.state = READ_BYTE;
break;
}
case 0x06:
{
/* WRITE ENABLE */
spi_eeprom.status |= 0x02;
spi_eeprom.state = STANDBY;
break;
}
default:
{
/* specific instructions (not supported) */
spi_eeprom.state = STANDBY;
break;
}
}
}
else
{
/* shift opcode value */
spi_eeprom.opcode = spi_eeprom.opcode << 1;
}
}
break;
}
case GET_ADDRESS:
{
/* latch data on CLK positive edge */
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
{
/* 16-bit address */
spi_eeprom.addr |= ((data >> BIT_DATA) & 1);
spi_eeprom.cycles++;
/* last bit ? */
if (spi_eeprom.cycles == 16)
{
/* reset cycles count */
spi_eeprom.cycles = 0;
/* mask unused address bits */
spi_eeprom.addr &= SIZE_MASK;
/* operation type */
if (spi_eeprom.opcode & 0x01)
{
/* READ operation */
spi_eeprom.buffer = Pico.sv.data[spi_eeprom.addr];
spi_eeprom.state = READ_BYTE;
}
else
{
/* WRITE operation */
spi_eeprom.buffer = 0;
spi_eeprom.state = WRITE_BYTE;
}
}
else
{
/* shift address value */
spi_eeprom.addr = spi_eeprom.addr << 1;
}
}
break;
}
case WRITE_BYTE:
{
/* latch data on CLK positive edge */
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
{
/* 8-bit data buffer */
spi_eeprom.buffer |= ((data >> BIT_DATA) & 1);
spi_eeprom.cycles++;
/* last bit ? */
if (spi_eeprom.cycles == 8)
{
/* reset cycles count */
spi_eeprom.cycles = 0;
/* write data to destination */
if (spi_eeprom.opcode & 0x01)
{
/* update status register */
spi_eeprom.status = (spi_eeprom.status & 0x02) | (spi_eeprom.buffer & 0x0c);
/* wait for operation end */
spi_eeprom.state = STANDBY;
}
else
{
/* Memory Array (write-protected) */
if (spi_eeprom.status & 2)
{
/* check array protection bits (BP0, BP1) */
switch ((spi_eeprom.status >> 2) & 0x03)
{
case 0x01:
{
/* $C000-$FFFF (sector #3) is protected */
if (spi_eeprom.addr < 0xC000)
{
Pico.sv.data[spi_eeprom.addr] = spi_eeprom.buffer;
}
break;
}
case 0x02:
{
/* $8000-$FFFF (sectors #2 and #3) is protected */
if (spi_eeprom.addr < 0x8000)
{
Pico.sv.data[spi_eeprom.addr] = spi_eeprom.buffer;
}
break;
}
case 0x03:
{
/* $0000-$FFFF (all sectors) is protected */
break;
}
default:
{
/* no sectors protected */
Pico.sv.data[spi_eeprom.addr] = spi_eeprom.buffer;
break;
}
}
}
/* reset data buffer */
spi_eeprom.buffer = 0;
/* increase array address (sequential writes are limited within the same page) */
spi_eeprom.addr = (spi_eeprom.addr & ~PAGE_MASK) | ((spi_eeprom.addr + 1) & PAGE_MASK);
}
}
else
{
/* shift data buffer value */
spi_eeprom.buffer = spi_eeprom.buffer << 1;
}
}
break;
}
case READ_BYTE:
{
/* output data on CLK positive edge */
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
{
/* read out bits */
spi_eeprom.out = (spi_eeprom.buffer >> (7 - spi_eeprom.cycles)) & 1;
spi_eeprom.cycles++;
/* last bit ? */
if (spi_eeprom.cycles == 8)
{
/* reset cycles count */
spi_eeprom.cycles = 0;
/* read from memory array ? */
if (spi_eeprom.opcode == 0x03)
{
/* read next array byte */
spi_eeprom.addr = (spi_eeprom.addr + 1) & SIZE_MASK;
spi_eeprom.buffer = Pico.sv.data[spi_eeprom.addr];
}
}
}
break;
}
default:
{
/* wait for !CS low->high transition */
break;
}
}
}
}
/* update input lines */
spi_eeprom.cs = (data >> BIT_CS) & 1;
spi_eeprom.clk = (data >> BIT_CLK) & 1;
}
unsigned int eeprom_spi_read(unsigned int address)
{
return (spi_eeprom.out << BIT_DATA);
}

View file

@ -1,47 +0,0 @@
/****************************************************************************
* Genesis Plus
* SPI Serial EEPROM (25XX512 only) support
*
* 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.
*
****************************************************************************************/
#ifndef _EEPROM_SPI_H_
#define _EEPROM_SPI_H_
/* Function prototypes */
extern void *eeprom_spi_init(int *size);
extern void eeprom_spi_write(unsigned char data);
extern unsigned int eeprom_spi_read(unsigned int address);
#endif

View file

@ -1,14 +1,13 @@
/*
* SSP1601 to ARM recompiler
* (C) notaz, 2008,2009,2010
* (C) irixxxx, 2019-2023
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include <pico/pico_int.h>
#include <cpu/drc/cmn.h>
#include "../../pico_int.h"
#include "../../../cpu/drc/cmn.h"
#include "compiler.h"
// FIXME: asm has these hardcoded
@ -40,7 +39,7 @@ void ssp_drc_end(void){}
#endif
#define COUNT_OP
#include <cpu/drc/emit_arm.c>
#include "../../../cpu/drc/emit_arm.c"
// -----------------------------------------------------
@ -360,7 +359,7 @@ static void tr_mov16(int r, int val)
static void tr_mov16_cond(int cond, int r, int val)
{
emith_move_r_imm_c(cond, r, val);
emith_op_imm(cond, 0, A_OP_MOV, r, val);
hostreg_r[r] = -1;
}
@ -477,7 +476,6 @@ static void tr_ptrr_mod(int r, int mod, int need_modulo, int count)
if (mod == 2)
known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] - count) & modulo);
else known_regs.r[r] = (known_regs.r[r] & ~modulo) | ((known_regs.r[r] + count) & modulo);
dirty_regb |= (1 << (r + 8));
}
else
{
@ -695,9 +693,9 @@ static int tr_aop_ssp2arm(int op)
/* spacial version of call for calling C needed on ios, since we use r9.. */
static void emith_call_c_func(void *target)
{
EOP_STMFD_SP(M2(7,9));
EOP_STMFD_SP(A_R7M|A_R9M);
emith_call(target);
EOP_LDMFD_SP(M2(7,9));
EOP_LDMFD_SP(A_R7M|A_R9M);
}
#else
#define emith_call_c_func emith_call
@ -844,7 +842,6 @@ static void tr_PMX_to_r0(int reg)
return;
}
tr_flush_dirty_pmcrs();
known_regb &= ~KRREG_PMC;
dirty_regb &= ~KRREG_PMC;
known_regb &= ~(1 << (20+reg));
@ -852,6 +849,7 @@ static void tr_PMX_to_r0(int reg)
// call the C code to handle this
tr_flush_dirty_ST();
//tr_flush_dirty_pmcrs();
tr_mov16(0, reg);
emith_call_c_func(ssp_pm_read);
hostreg_clear();
@ -991,7 +989,6 @@ static void tr_r0_to_ST(int const_val)
EOP_ORR_REG_LSL(6, 6, 1, 4); // orr r6, r6, r1, lsl #4
TR_WRITE_R0_TO_REG(SSP_ST);
hostreg_r[1] = -1;
known_regb &= ~KRREG_ST;
dirty_regb &= ~KRREG_ST;
}
@ -1024,9 +1021,9 @@ static void tr_r0_to_AL(int const_val)
hostreg_sspreg_changed(SSP_AL);
if (const_val != -1) {
known_regs.gr[SSP_A].l = const_val;
known_regb |= KRREG_AL;
known_regb |= 1 << SSP_AL;
} else
known_regb &= ~KRREG_AL;
known_regb &= ~(1 << SSP_AL);
}
static void tr_r0_to_PMX(int reg)
@ -1086,7 +1083,6 @@ static void tr_r0_to_PMX(int reg)
return;
}
tr_flush_dirty_pmcrs();
known_regb &= ~KRREG_PMC;
dirty_regb &= ~KRREG_PMC;
known_regb &= ~(1 << (25+reg));
@ -1094,6 +1090,7 @@ static void tr_r0_to_PMX(int reg)
// call the C code to handle this
tr_flush_dirty_ST();
//tr_flush_dirty_pmcrs();
tr_mov16(1, reg);
emith_call_c_func(ssp_pm_write);
hostreg_clear();
@ -1131,17 +1128,16 @@ static void tr_r0_to_PMC(int const_val)
known_regs.emu_status |= SSP_PMC_HAVE_ADDR;
known_regs.pmc.l = const_val;
}
dirty_regb |= KRREG_PMC;
}
else
{
tr_flush_dirty_ST();
if (dirty_regb & KRREG_PMC) {
if (known_regb & KRREG_PMC) {
emith_move_r_imm(1, known_regs.pmc.v);
EOP_STR_IMM(1,7,0x400+SSP_PMC*4);
known_regb &= ~KRREG_PMC;
dirty_regb &= ~KRREG_PMC;
}
known_regb &= ~KRREG_PMC;
EOP_LDR_IMM(1,7,0x484); // ldr r1, [r7, #0x484] // emu_status
EOP_ADD_IMM(2,7,24/2,4); // add r2, r7, #0x400
EOP_TST_IMM(1, 0, SSP_PMC_HAVE_ADDR);
@ -1249,7 +1245,7 @@ static int tr_detect_pm0_block(unsigned int op, int *pc, int imm)
EOP_ORR_IMM(6, 6, 24/2, 6); // orr r6, r6, 0x600
hostreg_sspreg_changed(SSP_ST);
known_regs.gr[SSP_ST].h = 0x60;
known_regb |= KRREG_ST;
known_regb |= 1 << SSP_ST;
dirty_regb &= ~KRREG_ST;
(*pc) += 3*2;
n_in_ops += 3;
@ -1438,13 +1434,16 @@ static int translate_op(unsigned int op, int *pc, int imm, int *end_cond, int *j
tmpv = tr_cond_check(op);
if (tmpv != A_COND_AL) {
jump_op = tcache_ptr;
EOP_C_B(tmpv, 0, 0); // placeholder for branch
EOP_MOV_IMM(0, 0, 0); // placeholder for branch
}
tr_mov16(0, *pc);
tr_r0_to_STACK(*pc);
if (tmpv != A_COND_AL)
EOP_C_B_PTR(jump_op, tr_neg_cond(tmpv), 0,
tcache_ptr - jump_op - 2);
if (tmpv != A_COND_AL) {
u32 *real_ptr = tcache_ptr;
tcache_ptr = jump_op;
EOP_C_B(tr_neg_cond(tmpv),0,real_ptr - jump_op - 2);
tcache_ptr = real_ptr;
}
tr_mov16_cond(tmpv, 0, imm);
if (tmpv != A_COND_AL)
tr_mov16_cond(tr_neg_cond(tmpv), 0, *pc);
@ -1518,8 +1517,8 @@ static int translate_op(unsigned int op, int *pc, int imm, int *end_cond, int *j
tr_make_dirty_ST();
EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_SUB,1,5,5,0,A_AM1_LSL,10); // subs r5, r5, r10
hostreg_sspreg_changed(SSP_A);
known_regb &= ~(KRREG_A|KRREG_AL);
dirty_regb |= KRREG_ST;
known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
ret++; break;
// mpya (rj), (ri), b
@ -1529,8 +1528,8 @@ static int translate_op(unsigned int op, int *pc, int imm, int *end_cond, int *j
tr_make_dirty_ST();
EOP_C_DOP_REG_XIMM(A_COND_AL,A_OP_ADD,1,5,5,0,A_AM1_LSL,10); // adds r5, r5, r10
hostreg_sspreg_changed(SSP_A);
known_regb &= ~(KRREG_A|KRREG_AL);
dirty_regb |= KRREG_ST;
known_regb &= ~(KRREG_A|KRREG_AL|KRREG_ST);
ret++; break;
// mld (rj), (ri), b
@ -1538,9 +1537,8 @@ static int translate_op(unsigned int op, int *pc, int imm, int *end_cond, int *j
EOP_C_DOP_IMM(A_COND_AL,A_OP_MOV,1,0,5,0,0); // movs r5, #0
hostreg_sspreg_changed(SSP_A);
known_regs.gr[SSP_A].v = 0;
dirty_regb |= KRREG_ST;
known_regb &= ~KRREG_ST;
known_regb |= (KRREG_A|KRREG_AL);
dirty_regb |= KRREG_ST;
tr_mac_load_XY(op);
ret++; break;
@ -1714,8 +1712,12 @@ static void *emit_block_epilogue(int cycles, int cond, int pc, int end_pc)
ssp_block_table[pc];
if (target != NULL)
emith_jump(target);
else
emith_jump(ssp_drc_next);
else {
int ops = emith_jump(ssp_drc_next);
end_ptr = tcache_ptr;
// cause the next block to be emitted over jump instruction
tcache_ptr -= ops;
}
}
else {
u32 *target1 = (pc < 0x400) ?
@ -1793,18 +1795,17 @@ void *ssp_translate_block(int pc)
tr_flush_dirty_ST();
tr_flush_dirty_pmcrs();
block_end = emit_block_epilogue(ccount, end_cond, jump_pc, pc);
emith_flush();
emith_pool_commit(-1);
if (tcache_ptr - (u32 *)tcache > DRC_TCACHE_SIZE/4) {
elprintf(EL_ANOMALY|EL_STATUS|EL_SVP, "tcache overflow!\n");
fflush(stdout);
exit(1);
}
// stats
nblocks++;
//printf("%i blocks, %i bytes, k=%.3f\n", nblocks, (u8 *)tcache_ptr - tcache,
// (double)((u8 *)tcache_ptr - tcache) / (double)n_in_ops);
//printf("%i blocks, %i bytes, k=%.3f\n", nblocks, (tcache_ptr - tcache)*4,
// (double)(tcache_ptr - tcache) / (double)n_in_ops);
#ifdef DUMP_BLOCK
{

View file

@ -26,8 +26,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <pico/pico_int.h>
#include <pico/memory.h>
#include "../../pico_int.h"
#include "../../memory.h"
// for wait loop det
static void PicoWrite16_dram(u32 a, u32 d)
@ -87,7 +87,7 @@ static u32 PicoRead16_svpr(u32 a)
a15004_looping = 0;
if (!a15004_looping)
elprintf(EL_SVP, "SVP r: [%06x] %04x @%06x", a, d, SekPc);
elprintf(EL_SVP, "SVP r%i: [%06x] %04x @%06x", realsize, a, d, SekPc);
if (a == 0xa15004 && !(d&1)) {
if (!a15004_looping)

View file

@ -206,7 +206,7 @@
* ops not used by VR are not implemented
*/
#include <pico/pico_int.h>
#include "../../pico_int.h"
#define u32 unsigned int
@ -474,8 +474,6 @@ static int get_inc(int mode)
static u32 pm_io(int reg, int write, u32 d)
{
unsigned int *pmac;
if (ssp->emu_status & SSP_PMC_SET)
{
// this MUST be blind r or w
@ -486,8 +484,7 @@ static u32 pm_io(int reg, int write, u32 d)
return 0;
}
elprintf(EL_SVP, "PM%i (%c) set to %08x @ %04x", reg, write ? 'w' : 'r', rPMC.v, GET_PPC_OFFS());
pmac = write ? ssp->pmac_write : ssp->pmac_read;
pmac[reg] = rPMC.v;
ssp->pmac_read[write ? reg + 6 : reg] = rPMC.v;
ssp->emu_status &= ~SSP_PMC_SET;
if ((rPMC.v & 0x7fffff) == 0x1c8000 || (rPMC.v & 0x7fffff) == 0x1c8240) {
elprintf(EL_SVP, "ssp IRAM copy from %06x to %04x", (ssp->RAM1[0]-1)<<1, (rPMC.v&0x7fff)<<1);
@ -576,8 +573,7 @@ static u32 pm_io(int reg, int write, u32 d)
}
// PMC value corresponds to last PMR accessed (not sure).
pmac = write ? ssp->pmac_write : ssp->pmac_read;
rPMC.v = pmac[reg];
rPMC.v = ssp->pmac_read[write ? reg + 6 : reg];
return d;
}

View file

@ -38,13 +38,8 @@ typedef union
{
unsigned int v;
struct {
#if CPU_IS_LE
unsigned short l;
unsigned short h;
#else
unsigned short h;
unsigned short l;
#endif
};
} ssp_reg_t;

View file

@ -6,9 +6,9 @@
@* See COPYING file in the top-level directory.
@*
#include <pico/arm_features.h>
#include "../../arm_features.h"
@.syntax unified
.syntax unified
.text
.align 2
@ -281,8 +281,8 @@ ssp_hle_902_loop:
bgt ssp_hle_902_loop
tst r12, #1
ldrneh r0, [r2], #2
strneh r0, [r3], #2
ldrhne r0, [r2], #2
strhne r0, [r3], #2
ldr r0, [r7, #SSP_OFFS_IRAM_ROM]
add r1, r7, #0x200
@ -501,7 +501,7 @@ FUNCTION(ssp_hle_07_036):
mov r12, #0x4000
orr r12,r12,#0x0018
subs r12,r3, r12
subnes r12,r12,#0x0400
subsne r12,r12,#0x0400
blne tr_unhandled
orr r2, r2, r2, lsl #16
@ -510,7 +510,7 @@ FUNCTION(ssp_hle_07_036):
hle_07_036_no_ovrwr:
tst r1, #2
strneh r2, [r1], #0x3e @ align
strhne r2, [r1], #0x3e @ align
subne r0, r0, #1
subs r0, r0, #4
blt hle_07_036_l2
@ -525,7 +525,7 @@ hle_07_036_l2:
tst r0, #2
strne r2, [r1], #0x40
tst r0, #1
strneh r2, [r1], #2
strhne r2, [r1], #2
b hle_07_036_end_copy
hle_07_036_ovrwr:
@ -562,10 +562,10 @@ hle_07_036_ol1:
hle_07_036_ol2:
tst r0, #1
ldrneh r3, [r1]
ldrhne r3, [r1]
andne r3, r3, r12
orrne r3, r3, r2
strneh r3, [r1], #2
strhne r3, [r1], #2
hle_07_036_end_copy:
ldr r2, [r7, #SSP_OFFS_DRAM]

View file

@ -30,9 +30,8 @@
#include <cpu/drc/cmn.h>
#include "compiler.h"
#define SVP_CYCLES_LINE 850
svp_t *svp = NULL;
int PicoSVPCycles = 850; // cycles/line, just a guess
static int svp_dyn_ready = 0;
/* save state stuff */
@ -58,7 +57,7 @@ static void PicoSVPReset(void)
memcpy(svp->iram_rom + 0x800, Pico.rom + 0x800, 0x20000 - 0x800);
ssp1601_reset(&svp->ssp1601);
#ifdef _SVP_DRC
if ((PicoIn.opt & POPT_EN_DRC) && svp_dyn_ready)
if ((PicoOpt & POPT_EN_DRC) && svp_dyn_ready)
ssp1601_dyn_reset(&svp->ssp1601);
#endif
}
@ -78,34 +77,37 @@ static void PicoSVPLine(void)
#endif
#ifdef _SVP_DRC
if ((PicoIn.opt & POPT_EN_DRC) && svp_dyn_ready)
ssp1601_dyn_run(SVP_CYCLES_LINE * count);
if ((PicoOpt & POPT_EN_DRC) && svp_dyn_ready)
ssp1601_dyn_run(PicoSVPCycles * count);
else
#endif
{
ssp1601_run(SVP_CYCLES_LINE * count);
ssp1601_run(PicoSVPCycles * count);
svp_dyn_ready = 0; // just in case
}
// test mode
//if (Pico.m.frame_count == 13) PicoIn.pad[0] |= 0xff;
//if (Pico.m.frame_count == 13) PicoPad[0] |= 0xff;
}
static int PicoSVPDma(u32 source, int len, unsigned short **base, u32 *mask)
static int PicoSVPDma(unsigned int source, int len, unsigned short **srcp, unsigned short **limitp)
{
if (source < Pico.romsize) // Rom
{
*base = (unsigned short *)(Pico.rom + (source & 0xfe0000));
*mask = 0x1ffff;
return source - 2;
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);
*base = (unsigned short *)svp->dram;
*mask = 0x1ffff;
return source - 2;
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);
@ -149,7 +151,7 @@ void PicoSVPStartup(void)
// init SVP compiler
svp_dyn_ready = 0;
#ifdef _SVP_DRC
if (PicoIn.opt & POPT_EN_DRC) {
if (PicoOpt & POPT_EN_DRC) {
if (ssp1601_dyn_startup())
return;
svp_dyn_ready = 1;
@ -168,6 +170,6 @@ void PicoSVPStartup(void)
svp_states[1].ptr = svp->dram;
svp_states[2].ptr = &svp->ssp1601;
carthw_chunks = svp_states;
PicoIn.AHW |= PAHW_SVP;
PicoAHW |= PAHW_SVP;
}

View file

@ -1,4 +1,4 @@
/* generated by tools/make_carthw_c, do not modify */
/* generated by ./tools/make_carthw_c, do not modify */
static const char builtin_carthw_cfg[] =
"[]\n"
"check_str=0x150,\"Virtua Racing\"\n"
@ -9,28 +9,12 @@ static const char builtin_carthw_cfg[] =
"check_str=0x810,\"OHMP\"\n"
"hw=svp\n"
"[]\n"
"check_str=0x100,\"SEGA IAC \"\n"
"check_str=0x100,\"SEGA PICO\"\n"
"hw=pico\n"
"[]\n"
"check_str=0x100,\"IMA IKUNO\"\n"
"check_str=0x100,\"IMA IKUNOUJYUKU\"\n"
"hw=pico\n"
"[]\n"
"check_str=0x120,\"32X SAMPLE PROGRAM\"\n"
"check_str=0x32b74c,\"Bishop Level\"\n"
"prop=force_6btn\n"
"[]\n"
"check_str=0x100,\"SEGA 32X\"\n"
"check_str=0x150,\"WWF RAW\"\n"
"prop=wwfraw_hack\n"
"[]\n"
"check_str=0x100,\"SEGA 32X\"\n"
"check_str=0x120,\"BLACKTHORNE\"\n"
"prop=blackthorne_hack\n"
"[]\n"
"check_str=0x100,\"SEGA\"\n"
"check_str=0x150,\"MARS CHECK PROGRAM\"\n"
"prop=marscheck_hack\n"
"[]\n"
"check_str=0x120,\"PUGGSY\"\n"
"prop=no_sram\n"
"[]\n"
@ -40,11 +24,9 @@ static const char builtin_carthw_cfg[] =
"check_str=0x150,\"MICRO MACHINES II\"\n"
"prop=filled_sram\n"
"[]\n"
"check_str=0x150,\" HardBall III\"\n"
"sram_range=0x200000,0x20ffff\n"
"[]\n"
"check_str=0x100,\"SEGA SSF\"\n"
"hw=ssf2_mapper\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"
@ -54,18 +36,6 @@ static const char builtin_carthw_cfg[] =
"check_str=0x610,\"Respect\"\n"
"hw=piersolar_mapper\n"
"[]\n"
"check_str=0x150,\"BEGGAR PRINCE\"\n"
"hw=sf001_mapper\n"
"sram_range=0x400000,0x40ffff\n"
"prop=filled_sram\n"
"[]\n"
"check_str=0x150,\"LEGEND OF WUKONG\"\n"
"hw=sf002_mapper\n"
"[]\n"
"check_str=0x150,\"STAR ODYSSEY\"\n"
"hw=sf004_mapper\n"
"sram_range=0x200000,0x207fff\n"
"[]\n"
"check_str=0x120,\"FLICKY\"\n"
"check_size_gt=0x020000\n"
"hw=x_in_1_mapper\n"
@ -78,14 +48,6 @@ static const char builtin_carthw_cfg[] =
"check_size_gt=0x080000\n"
"hw=x_in_1_mapper\n"
"[]\n"
"check_str=0x150,\"TINY TOON ADVENTURES\"\n"
"check_size_gt=0x080000\n"
"hw=x_in_1_mapper\n"
"[]\n"
"check_str=0x160,\"FS MOONWALKER\"\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"
@ -98,11 +60,6 @@ static const char builtin_carthw_cfg[] =
"check_size_gt=0x100000\n"
"hw=radica_mapper\n"
"[]\n"
"check_str=0x150,\"STREET FIGHTER\"\n"
"check_str=0x161,\"SPECIAL CHAMPION EDITION\"\n"
"check_size_gt=0x300000\n"
"hw=radica_mapper\n"
"[]\n"
"check_str=0x94,\"THE EARTH DEFEND\"\n"
"hw=realtec_mapper\n"
"[]\n"
@ -120,11 +77,6 @@ static const char builtin_carthw_cfg[] =
"eeprom_type=3\n"
"eeprom_lines=8,0,0\n"
"[]\n"
"check_str=0x150,\"GREATEST HEAVYWEIGHTS\"\n"
"sram_range=0x200000,0x200001\n"
"eeprom_type=1\n"
"eeprom_lines=1,0,0\n"
"[]\n"
"check_str=0x150,\"MICRO MACHINES II\"\n"
"sram_range=0x300000,0x380001\n"
"eeprom_type=2\n"
@ -182,182 +134,62 @@ static const char builtin_carthw_cfg[] =
"eeprom_type=1\n"
"eeprom_lines=6,7,7\n"
"[]\n"
"check_str=0x150,\"MLBPA SPORTS TALK BASEBALL\"\n"
"sram_range=0x200000,0x200001\n"
"eeprom_type=1\n"
"eeprom_lines=1,0,0\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xc9706e25\n"
"hw=lk3_mapper\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0x4c98cc30\n"
"hw=lk3_mapper\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0x6ec032cb\n"
"hw=lk3_mapper\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0x0d097f5c\n"
"hw=lk3_mapper\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xbf7219df\n"
"hw=lk3_mapper\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xb5b7606e\n"
"hw=lk3_mapper\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xab3ae5e9\n"
"hw=lk3_mapper\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0x802f53f9\n"
"hw=lk3_mapper\n"
"[]\n"
"check_csum=0\n"
"check_crc32=0xf63b7bdc\n"
"hw=smw64_mapper\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0x50aa5a9b\n"
"check_crc32=0x10458e09\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,0xffff00,0x28\n"
"[]\n"
"check_csum=0\n"
"check_crc32=0xee20be2c\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x0c\n"
"[]\n"
"check_str=0x104,\"SEGASEGASEGA\"\n"
"check_crc32=0xc3616596\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x1c\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0x7861fb28\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x0a\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xf4cb9b37\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x00\n"
"prot_ro_value16=0xa13002,-2,0x01\n"
"prot_ro_value16=0xa1303e,-2,0x1f\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0x7bdfb390\n"
"hw=prot\n"
"prot_ro_value16=0xa13000,-2,0x00\n"
"prot_ro_value16=0xa13002,-2,0x01\n"
"prot_ro_value16=0xa1303e,-2,0x1f\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0x8fb8b29e\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\n"
"[]\n"
"check_str=0x104,\" MEGA DRIVE (C)\"\n"
"check_str=0x118,\"CREATON.\"\n"
"check_str=0x180,\"MDGM-000\"\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x9000\n"
"prot_ro_value16=0x401000,-2,0xd300\n"
"[]\n"
"check_csum=0x6cca\n"
"check_crc32=0xab5d5d9e\n"
"hw=prot\n"
"prot_ro_value16=0x500008,-2,0x5000\n"
"[]\n"
"check_str=0x113,\"KANKO 91-92\"\n"
"check_crc32=0x79423515\n"
"hw=prot\n"
"prot_ro_value16=0x500008,-2,0x5000\n"
"prot_ro_value16=0x500208,-2,0xa000\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0x7009cac3\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00004,0\n"
"prot_rw_value16=0x400004,0xc00004,0\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0x1c602dd4\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00000,0\n"
"prot_rw_value16=0x400004,0xc00004,0\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xc31cfcca\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00000,0\n"
"prot_rw_value16=0x400004,0xc00004,0\n"
"[]\n"
"check_csum=0x30b9\n"
"check_crc32=0x35e0ff17\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00000,0\n"
"prot_rw_value16=0x400004,0xc00004,0\n"
"[]\n"
"check_csum=0x5ff9\n"
"check_crc32=0x4b2b163a\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00000,0\n"
"prot_rw_value16=0x400004,0xc00004,0\n"
"[]\n"
"check_csum=0x6001\n"
"check_crc32=0xfa80956a\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00000,0\n"
"prot_rw_value16=0x400004,0xc00004,0\n"
"[]\n"
"check_csum=0xffff\n"
"check_crc32=0x91865ea4\n"
"hw=prot\n"
"prot_rw_value16=0x400000,0xc00000,0\n"
"prot_rw_value16=0x400004,0xc00004,0\n"
"[]\n"
"check_csum=0xffff\n"
"check_crc32=0x8e83dbfa\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x6300\n"
"prot_ro_value16=0x400002,-2,0x9800\n"
"prot_ro_value16=0x400004,-2,0xc900\n"
"prot_ro_value16=0x400006,-2,0x1800\n"
"[]\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xf838aa3b\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x6300\n"
"prot_ro_value16=0x400002,-2,0x9800\n"
"prot_ro_value16=0x400004,-2,0xc900\n"
"prot_ro_value16=0x400006,-2,0x1800\n"
"[]\n"
"check_str=0x172,\"GAME : ELF WOR\"\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x5500\n"
"prot_ro_value16=0x400002,-2,0x0f00\n"
"prot_ro_value16=0x400004,-2,0xc900\n"
"prot_ro_value16=0x400006,-2,0x1800\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=0x5fdeb37b\n"
"check_str=0x104,\" \"\n"
"check_crc32=0xcbc38eea\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x5500\n"
"prot_ro_value16=0x400002,-2,0x0f00\n"
"prot_ro_value16=0x400004,-2,0xc900\n"
"prot_ro_value16=0x400006,-2,0x1800\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=0xc9539fce\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"
@ -365,63 +197,33 @@ static const char builtin_carthw_cfg[] =
"prot_ro_value16=0x400006,-2,0xf000\n"
"[]\n"
"check_str=0x104,\" \"\n"
"check_crc32=0x6a95f766\n"
"check_crc32=0xf26f88d1\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x6300\n"
"prot_ro_value16=0x400002,-2,0x9800\n"
"prot_ro_value16=0x400004,-2,0xaa00\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=0xf93f3d0b\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=0x66165305\n"
"check_crc32=0x413dfee2\n"
"hw=prot_lk3\n"
"[]\n"
"check_str=0x140,\"SUPER MARIO BROS \"\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"
"prot_ro_value16=0xa13000,-2,0x0c\n"
"[]\n"
"check_str=0xfe,\"WISEGAME\"\n"
"check_crc32=0x6f01bd65\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xf7e1b3e1\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"
"prot_ro_value16=0xa13000,-2,0x0a\n"
"[]\n"
"check_str=0xfe,\"WISEGAME IS TRADE MARKER\"\n"
"check_str=0x104,\" are Registered Trademarks\"\n"
"check_crc32=0xb8261ff5\n"
"hw=prot\n"
"prot_ro_value16=0x400002,-2,0xaa00\n"
"prot_ro_value16=0x400004,-2,0xc900\n"
"prot_ro_value16=0x400006,-2,0xf000\n"
"[]\n"
"check_csum=0xffff\n"
"check_crc32=0xdd02797c\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_csum=0\n"
"check_crc32=0xee9fc429\n"
"hw=prot\n"
"prot_ro_value16=0x400000,-2,0x6300\n"
"[]\n"
"check_str=0x180,\"GM 00000000-00\"\n"
"check_crc32=0x6732aab4\n"
"prop=no_z80_bus_lock\n"
"[]\n"
"check_str=0x180,\"GM 00000000-00\"\n"
"check_crc32=0xe302585a\n"
"prop=no_z80_bus_lock\n"
"[]\n"
"check_csum=8224\n"
"check_crc32=0x20ed0de8\n"
"prop=no_z80_bus_lock\n"
"prot_rw_value16=0x400000,0xc00000,0\n"
;

637
pico/cd/LC89510.c Normal file
View file

@ -0,0 +1,637 @@
/***********************************************************
* *
* This source file was taken from the Gens project *
* Written by Stéphane Dallongeville *
* Copyright (c) 2002 by Stéphane Dallongeville *
* Modified/adapted for PicoDrive by notaz, 2007 *
* *
***********************************************************/
#include "../pico_int.h"
#define CDC_DMA_SPEED 256
static void CDD_Reset(void)
{
// Reseting CDD
memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control
Pico_mcd->cdd.Status = 0;
Pico_mcd->cdd.Minute = 0;
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
// clear receive status and transfer command
memset(Pico_mcd->s68k_regs+0x38, 0, 20);
Pico_mcd->s68k_regs[0x38+9] = 0xF; // Default checksum
}
static void CDC_Reset(void)
{
// Reseting CDC
memset(Pico_mcd->cdc.Buffer, 0, sizeof(Pico_mcd->cdc.Buffer));
Pico_mcd->cdc.COMIN = 0;
Pico_mcd->cdc.IFSTAT = 0xFF;
Pico_mcd->cdc.DAC.N = 0;
Pico_mcd->cdc.DBC.N = 0;
Pico_mcd->cdc.HEAD.N = 0x01000000;
Pico_mcd->cdc.PT.N = 0;
Pico_mcd->cdc.WA.N = 2352 * 2;
Pico_mcd->cdc.STAT.N = 0x00000080;
Pico_mcd->cdc.SBOUT = 0;
Pico_mcd->cdc.IFCTRL = 0;
Pico_mcd->cdc.CTRL.N = 0;
Pico_mcd->cdc.Decode_Reg_Read = 0;
Pico_mcd->scd.Status_CDC &= ~0x08;
}
PICO_INTERNAL void LC89510_Reset(void)
{
CDD_Reset();
CDC_Reset();
// clear DMA_Adr & Stop_Watch
memset(Pico_mcd->s68k_regs + 0xA, 0, 4);
}
PICO_INTERNAL void Update_CDC_TRansfer(int which)
{
unsigned int DMA_Adr, dep, length;
unsigned short *dest;
unsigned char *src;
if (1) //Pico_mcd->cdc.DBC.N <= (CDC_DMA_SPEED * 2))
{
length = (Pico_mcd->cdc.DBC.N + 1) >> 1;
Pico_mcd->scd.Status_CDC &= ~0x08; // Last transfer
Pico_mcd->s68k_regs[4] |= 0x80; // End data transfer
Pico_mcd->s68k_regs[4] &= ~0x40; // no more data ready
Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress
if (Pico_mcd->cdc.IFCTRL & 0x40) // DTEIEN = Data Trasnfer End Interrupt Enable ?
{
Pico_mcd->cdc.IFSTAT &= ~0x40;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN5)
{
elprintf(EL_INTS, "cdc DTE irq 5");
SekInterruptS68k(5);
}
}
}
else length = CDC_DMA_SPEED;
// TODO: dst bounds checking?
src = Pico_mcd->cdc.Buffer + Pico_mcd->cdc.DAC.N;
DMA_Adr = (Pico_mcd->s68k_regs[0xA]<<8) | Pico_mcd->s68k_regs[0xB];
if (which == 7) // WORD RAM
{
if (Pico_mcd->s68k_regs[3] & 4)
{
// test: Final Fight
int bank = !(Pico_mcd->s68k_regs[3]&1);
dep = ((DMA_Adr & 0x3FFF) << 3);
cdprintf("CD DMA # %04x -> word_ram1M # %06x, len=%i",
Pico_mcd->cdc.DAC.N, dep, length);
dest = (unsigned short *) (Pico_mcd->word_ram1M[bank] + dep);
memcpy16bswap(dest, src, length);
/*{ // debug
unsigned char *b1 = Pico_mcd->word_ram1M[bank] + dep;
unsigned char *b2 = (unsigned char *)(dest+length) - 8;
dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x",
b1[0], b1[1], b1[4], b1[5], b2[0], b2[1], b2[4], b2[5]);
}*/
}
else
{
dep = ((DMA_Adr & 0x7FFF) << 3);
cdprintf("CD DMA # %04x -> word_ram2M # %06x, len=%i",
Pico_mcd->cdc.DAC.N, dep, length);
dest = (unsigned short *) (Pico_mcd->word_ram2M + dep);
memcpy16bswap(dest, src, length);
/*{ // debug
unsigned char *b1 = Pico_mcd->word_ram2M + dep;
unsigned char *b2 = (unsigned char *)(dest+length) - 4;
dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x",
b1[0], b1[1], b1[2], b1[3], b2[0], b2[1], b2[2], b2[3]);
}*/
}
}
else if (which == 4) // PCM RAM (check: popful Mail)
{
dep = (DMA_Adr & 0x03FF) << 2;
cdprintf("CD DMA # %04x -> PCM[%i] # %04x, len=%i",
Pico_mcd->cdc.DAC.N, Pico_mcd->pcm.bank, dep, length);
dest = (unsigned short *) (Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank] + dep);
if (Pico_mcd->cdc.DAC.N & 1) /* unaligned src? */
memcpy(dest, src, length*2);
else memcpy16(dest, (unsigned short *) src, length);
}
else if (which == 5) // PRG RAM
{
dep = DMA_Adr << 3;
dest = (unsigned short *) (Pico_mcd->prg_ram + dep);
cdprintf("CD DMA # %04x -> prg_ram # %06x, len=%i",
Pico_mcd->cdc.DAC.N, dep, length);
memcpy16bswap(dest, src, length);
/*{ // debug
unsigned char *b1 = Pico_mcd->prg_ram + dep;
unsigned char *b2 = (unsigned char *)(dest+length) - 4;
dprintf("%02x %02x %02x %02x .. %02x %02x %02x %02x",
b1[0], b1[1], b1[2], b1[3], b2[0], b2[1], b2[2], b2[3]);
}*/
}
length <<= 1;
Pico_mcd->cdc.DAC.N = (Pico_mcd->cdc.DAC.N + length) & 0xFFFF;
if (Pico_mcd->scd.Status_CDC & 0x08) Pico_mcd->cdc.DBC.N -= length;
else Pico_mcd->cdc.DBC.N = 0;
// update DMA_Adr
length >>= 2;
if (which != 4) length >>= 1;
DMA_Adr += length;
Pico_mcd->s68k_regs[0xA] = DMA_Adr >> 8;
Pico_mcd->s68k_regs[0xB] = DMA_Adr;
}
PICO_INTERNAL_ASM unsigned short Read_CDC_Host(int is_sub)
{
int addr;
if (!(Pico_mcd->scd.Status_CDC & 0x08))
{
// Transfer data disabled
cdprintf("Read_CDC_Host FIXME: Transfer data disabled");
return 0;
}
if ((is_sub && (Pico_mcd->s68k_regs[4] & 7) != 3) ||
(!is_sub && (Pico_mcd->s68k_regs[4] & 7) != 2))
{
// Wrong setting
cdprintf("Read_CDC_Host FIXME: Wrong setting");
return 0;
}
Pico_mcd->cdc.DBC.N -= 2;
if (Pico_mcd->cdc.DBC.N <= 0)
{
Pico_mcd->cdc.DBC.N = 0;
Pico_mcd->scd.Status_CDC &= ~0x08; // Last transfer
Pico_mcd->s68k_regs[4] |= 0x80; // End data transfer
Pico_mcd->s68k_regs[4] &= ~0x40; // no more data ready
Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress
if (Pico_mcd->cdc.IFCTRL & 0x40) // DTEIEN = Data Transfer End Interrupt Enable ?
{
Pico_mcd->cdc.IFSTAT &= ~0x40;
if (Pico_mcd->s68k_regs[0x33]&(1<<5)) {
elprintf(EL_INTS, "m68k: s68k irq 5");
SekInterruptS68k(5);
}
cdprintf("CDC - DTE interrupt");
}
}
addr = Pico_mcd->cdc.DAC.N;
Pico_mcd->cdc.DAC.N += 2;
cdprintf("Read_CDC_Host sub=%i d=%04x dac=%04x dbc=%04x", is_sub,
(Pico_mcd->cdc.Buffer[addr]<<8) | Pico_mcd->cdc.Buffer[addr+1], Pico_mcd->cdc.DAC.N, Pico_mcd->cdc.DBC.N);
return (Pico_mcd->cdc.Buffer[addr]<<8) | Pico_mcd->cdc.Buffer[addr+1];
}
PICO_INTERNAL void CDC_Update_Header(void)
{
if (Pico_mcd->cdc.CTRL.B.B1 & 0x01) // Sub-Header wanted ?
{
Pico_mcd->cdc.HEAD.B.B0 = 0;
Pico_mcd->cdc.HEAD.B.B1 = 0;
Pico_mcd->cdc.HEAD.B.B2 = 0;
Pico_mcd->cdc.HEAD.B.B3 = 0;
}
else
{
_msf MSF;
LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);
Pico_mcd->cdc.HEAD.B.B0 = INT_TO_BCDB(MSF.M);
Pico_mcd->cdc.HEAD.B.B1 = INT_TO_BCDB(MSF.S);
Pico_mcd->cdc.HEAD.B.B2 = INT_TO_BCDB(MSF.F);
Pico_mcd->cdc.HEAD.B.B3 = 0x01;
}
}
PICO_INTERNAL unsigned char CDC_Read_Reg(void)
{
unsigned char ret;
switch(Pico_mcd->s68k_regs[5] & 0xF)
{
case 0x0: // COMIN
cdprintf("CDC read reg 00 = %.2X", Pico_mcd->cdc.COMIN);
Pico_mcd->s68k_regs[5] = 0x1;
return Pico_mcd->cdc.COMIN;
case 0x1: // IFSTAT
cdprintf("CDC read reg 01 = %.2X", Pico_mcd->cdc.IFSTAT);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 1); // Reg 1 (decoding)
Pico_mcd->s68k_regs[5] = 0x2;
return Pico_mcd->cdc.IFSTAT;
case 0x2: // DBCL
cdprintf("CDC read reg 02 = %.2X", Pico_mcd->cdc.DBC.B.L);
Pico_mcd->s68k_regs[5] = 0x3;
return Pico_mcd->cdc.DBC.B.L;
case 0x3: // DBCH
cdprintf("CDC read reg 03 = %.2X", Pico_mcd->cdc.DBC.B.H);
Pico_mcd->s68k_regs[5] = 0x4;
return Pico_mcd->cdc.DBC.B.H;
case 0x4: // HEAD0
cdprintf("CDC read reg 04 = %.2X", Pico_mcd->cdc.HEAD.B.B0);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 4); // Reg 4 (decoding)
Pico_mcd->s68k_regs[5] = 0x5;
return Pico_mcd->cdc.HEAD.B.B0;
case 0x5: // HEAD1
cdprintf("CDC read reg 05 = %.2X", Pico_mcd->cdc.HEAD.B.B1);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 5); // Reg 5 (decoding)
Pico_mcd->s68k_regs[5] = 0x6;
return Pico_mcd->cdc.HEAD.B.B1;
case 0x6: // HEAD2
cdprintf("CDC read reg 06 = %.2X", Pico_mcd->cdc.HEAD.B.B2);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 6); // Reg 6 (decoding)
Pico_mcd->s68k_regs[5] = 0x7;
return Pico_mcd->cdc.HEAD.B.B2;
case 0x7: // HEAD3
cdprintf("CDC read reg 07 = %.2X", Pico_mcd->cdc.HEAD.B.B3);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 7); // Reg 7 (decoding)
Pico_mcd->s68k_regs[5] = 0x8;
return Pico_mcd->cdc.HEAD.B.B3;
case 0x8: // PTL
cdprintf("CDC read reg 08 = %.2X", Pico_mcd->cdc.PT.B.L);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 8); // Reg 8 (decoding)
Pico_mcd->s68k_regs[5] = 0x9;
return Pico_mcd->cdc.PT.B.L;
case 0x9: // PTH
cdprintf("CDC read reg 09 = %.2X", Pico_mcd->cdc.PT.B.H);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 9); // Reg 9 (decoding)
Pico_mcd->s68k_regs[5] = 0xA;
return Pico_mcd->cdc.PT.B.H;
case 0xA: // WAL
cdprintf("CDC read reg 10 = %.2X", Pico_mcd->cdc.WA.B.L);
Pico_mcd->s68k_regs[5] = 0xB;
return Pico_mcd->cdc.WA.B.L;
case 0xB: // WAH
cdprintf("CDC read reg 11 = %.2X", Pico_mcd->cdc.WA.B.H);
Pico_mcd->s68k_regs[5] = 0xC;
return Pico_mcd->cdc.WA.B.H;
case 0xC: // STAT0
cdprintf("CDC read reg 12 = %.2X", Pico_mcd->cdc.STAT.B.B0);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 12); // Reg 12 (decoding)
Pico_mcd->s68k_regs[5] = 0xD;
return Pico_mcd->cdc.STAT.B.B0;
case 0xD: // STAT1
cdprintf("CDC read reg 13 = %.2X", Pico_mcd->cdc.STAT.B.B1);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 13); // Reg 13 (decoding)
Pico_mcd->s68k_regs[5] = 0xE;
return Pico_mcd->cdc.STAT.B.B1;
case 0xE: // STAT2
cdprintf("CDC read reg 14 = %.2X", Pico_mcd->cdc.STAT.B.B2);
Pico_mcd->cdc.Decode_Reg_Read |= (1 << 14); // Reg 14 (decoding)
Pico_mcd->s68k_regs[5] = 0xF;
return Pico_mcd->cdc.STAT.B.B2;
case 0xF: // STAT3
cdprintf("CDC read reg 15 = %.2X", Pico_mcd->cdc.STAT.B.B3);
ret = Pico_mcd->cdc.STAT.B.B3;
Pico_mcd->cdc.IFSTAT |= 0x20; // decoding interrupt flag cleared
if ((Pico_mcd->cdc.CTRL.B.B0 & 0x80) && (Pico_mcd->cdc.IFCTRL & 0x20))
{
if ((Pico_mcd->cdc.Decode_Reg_Read & 0x73F2) == 0x73F2)
Pico_mcd->cdc.STAT.B.B3 = 0x80;
}
return ret;
}
return 0;
}
PICO_INTERNAL void CDC_Write_Reg(unsigned char Data)
{
cdprintf("CDC write reg%02d = %.2X", Pico_mcd->s68k_regs[5] & 0xF, Data);
switch (Pico_mcd->s68k_regs[5] & 0xF)
{
case 0x0: // SBOUT
Pico_mcd->s68k_regs[5] = 0x1;
Pico_mcd->cdc.SBOUT = Data;
break;
case 0x1: // IFCTRL
Pico_mcd->s68k_regs[5] = 0x2;
Pico_mcd->cdc.IFCTRL = Data;
if ((Pico_mcd->cdc.IFCTRL & 0x02) == 0) // Stop data transfer
{
Pico_mcd->cdc.DBC.N = 0;
Pico_mcd->scd.Status_CDC &= ~0x08;
Pico_mcd->cdc.IFSTAT |= 0x08; // No more data transfer in progress
}
break;
case 0x2: // DBCL
Pico_mcd->s68k_regs[5] = 0x3;
Pico_mcd->cdc.DBC.B.L = Data;
break;
case 0x3: // DBCH
Pico_mcd->s68k_regs[5] = 0x4;
Pico_mcd->cdc.DBC.B.H = Data;
break;
case 0x4: // DACL
Pico_mcd->s68k_regs[5] = 0x5;
Pico_mcd->cdc.DAC.B.L = Data;
break;
case 0x5: // DACH
Pico_mcd->s68k_regs[5] = 0x6;
Pico_mcd->cdc.DAC.B.H = Data;
break;
case 0x6: // DTTRG
if (Pico_mcd->cdc.IFCTRL & 0x02) // Data transfer enable ?
{
Pico_mcd->cdc.IFSTAT &= ~0x08; // Data transfer in progress
Pico_mcd->scd.Status_CDC |= 0x08; // Data transfer in progress
Pico_mcd->s68k_regs[4] &= 0x7F; // A data transfer start
cdprintf("************** Starting Data Transfer ***********");
cdprintf("RS0 = %.4X DAC = %.4X DBC = %.4X DMA adr = %.4X\n\n", Pico_mcd->s68k_regs[4]<<8,
Pico_mcd->cdc.DAC.N, Pico_mcd->cdc.DBC.N, (Pico_mcd->s68k_regs[0xA]<<8) | Pico_mcd->s68k_regs[0xB]);
// tmp
{
int ddx = Pico_mcd->s68k_regs[4] & 7;
if (ddx < 2) break; // invalid
if (ddx < 4) {
Pico_mcd->s68k_regs[4] |= 0x40; // Data set ready in host port
break;
}
if (ddx == 6) break; // invalid
pcd_event_schedule_s68k(PCD_EVENT_DMA, Pico_mcd->cdc.DBC.N / 2);
}
}
break;
case 0x7: // DTACK
Pico_mcd->cdc.IFSTAT |= 0x40; // end data transfer interrupt flag cleared
break;
case 0x8: // WAL
Pico_mcd->s68k_regs[5] = 0x9;
Pico_mcd->cdc.WA.B.L = Data;
break;
case 0x9: // WAH
Pico_mcd->s68k_regs[5] = 0xA;
Pico_mcd->cdc.WA.B.H = Data;
break;
case 0xA: // CTRL0
Pico_mcd->s68k_regs[5] = 0xB;
Pico_mcd->cdc.CTRL.B.B0 = Data;
break;
case 0xB: // CTRL1
Pico_mcd->s68k_regs[5] = 0xC;
Pico_mcd->cdc.CTRL.B.B1 = Data;
break;
case 0xC: // PTL
Pico_mcd->s68k_regs[5] = 0xD;
Pico_mcd->cdc.PT.B.L = Data;
break;
case 0xD: // PTH
Pico_mcd->s68k_regs[5] = 0xE;
Pico_mcd->cdc.PT.B.H = Data;
break;
case 0xE: // CTRL2
Pico_mcd->cdc.CTRL.B.B2 = Data;
break;
case 0xF: // RESET
CDC_Reset();
break;
}
}
static int bswapwrite(int a, unsigned short d)
{
*(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8);
return d + (d >> 8);
}
PICO_INTERNAL void CDD_Export_Status(void)
{
unsigned int csum;
csum = bswapwrite( 0x38+0, Pico_mcd->cdd.Status);
csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute);
csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde);
csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame);
Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext;
csum += Pico_mcd->cdd.Ext;
Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf;
Pico_mcd->s68k_regs[0x37] &= 3; // CDD.Control
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4)
{
elprintf(EL_INTS, "cdd export irq 4");
SekInterruptS68k(4);
}
// cdprintf("CDD exported status\n");
cdprintf("out: Status=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X",
(Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1],
(Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3],
(Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5],
(Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7],
(Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]);
}
PICO_INTERNAL void CDD_Import_Command(void)
{
// cdprintf("CDD importing command\n");
cdprintf("in: Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X Checksum=%.4X",
(Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1],
(Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3],
(Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5],
(Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7],
(Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]);
switch (Pico_mcd->s68k_regs[0x38+10+0])
{
case 0x0: // STATUS (?)
Get_Status_CDD_c0();
break;
case 0x1: // STOP ALL (?)
Stop_CDD_c1();
break;
case 0x2: // GET TOC INFORMATIONS
switch(Pico_mcd->s68k_regs[0x38+10+3])
{
case 0x0: // get current position (MSF format)
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00);
Get_Pos_CDD_c20();
break;
case 0x1: // get elapsed time of current track played/scanned (relative MSF format)
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1;
Get_Track_Pos_CDD_c21();
break;
case 0x2: // get current track in RS2-RS3
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 2;
Get_Current_Track_CDD_c22();
break;
case 0x3: // get total length (MSF format)
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3;
Get_Total_Lenght_CDD_c23();
break;
case 0x4: // first & last track number
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4;
Get_First_Last_Track_CDD_c24();
break;
case 0x5: // get track addresse (MSF format)
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5;
Get_Track_Adr_CDD_c25();
break;
default : // invalid, then we return status
Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF;
Get_Status_CDD_c0();
break;
}
break;
case 0x3: // READ
Play_CDD_c3();
break;
case 0x4: // SEEK
Seek_CDD_c4();
break;
case 0x6: // PAUSE/STOP
Pause_CDD_c6();
break;
case 0x7: // RESUME
Resume_CDD_c7();
break;
case 0x8: // FAST FOWARD
Fast_Foward_CDD_c8();
break;
case 0x9: // FAST REWIND
Fast_Rewind_CDD_c9();
break;
case 0xA: // RECOVER INITIAL STATE (?)
CDD_cA();
break;
case 0xC: // CLOSE TRAY
Close_Tray_CDD_cC();
break;
case 0xD: // OPEN TRAY
Open_Tray_CDD_cD();
break;
default: // UNKNOWN
CDD_Def();
break;
}
}

135
pico/cd/LC89510.h Normal file
View file

@ -0,0 +1,135 @@
/***********************************************************
* *
* This source was taken from the Gens project *
* Written by Stéphane Dallongeville *
* Copyright (c) 2002 by Stéphane Dallongeville *
* Modified/adapted for PicoDrive by notaz, 2007 *
* *
***********************************************************/
#ifndef _LC89510_H
#define _LC89510_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
unsigned char Buffer[(32 * 1024 * 2) + 2352];
// unsigned int Host_Data; // unused
// unsigned int DMA_Adr; // 0A
// unsigned int Stop_Watch; // 0C
unsigned int COMIN;
unsigned int IFSTAT;
union
{
struct
{
unsigned char L;
unsigned char H;
unsigned short unused;
} B;
int N;
} DBC;
union
{
struct
{
unsigned char L;
unsigned char H;
unsigned short unused;
} B;
int N;
} DAC;
union
{
struct
{
unsigned char B0;
unsigned char B1;
unsigned char B2;
unsigned char B3;
} B;
unsigned int N;
} HEAD;
union
{
struct
{
unsigned char L;
unsigned char H;
unsigned short unused;
} B;
int N;
} PT;
union
{
struct
{
unsigned char L;
unsigned char H;
unsigned short unused;
} B;
int N;
} WA;
union
{
struct
{
unsigned char B0;
unsigned char B1;
unsigned char B2;
unsigned char B3;
} B;
unsigned int N;
} STAT;
unsigned int SBOUT;
unsigned int IFCTRL;
union
{
struct
{
unsigned char B0;
unsigned char B1;
unsigned char B2;
unsigned char B3;
} B;
unsigned int N;
} CTRL;
unsigned int Decode_Reg_Read;
} CDC;
typedef struct
{
// unsigned short Fader; // 34
// unsigned short Control; // 36
// unsigned short Cur_Comm;// unused
// "Receive status"
unsigned short Status;
unsigned short Minute;
unsigned short Seconde;
unsigned short Frame;
unsigned char Ext;
unsigned char pad[3];
} CDD;
PICO_INTERNAL_ASM unsigned short Read_CDC_Host(int is_sub);
PICO_INTERNAL void LC89510_Reset(void);
PICO_INTERNAL void Update_CDC_TRansfer(int which);
PICO_INTERNAL void CDC_Update_Header(void);
PICO_INTERNAL unsigned char CDC_Read_Reg(void);
PICO_INTERNAL void CDC_Write_Reg(unsigned char Data);
PICO_INTERNAL void CDD_Export_Status(void);
PICO_INTERNAL void CDD_Import_Command(void);
#ifdef __cplusplus
};
#endif
#endif

151
pico/cd/buffering.c Normal file
View file

@ -0,0 +1,151 @@
/*
* Buffering handling
* (C) notaz, 2007,2008
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
int PicoCDBuffers = 0;
static unsigned char *cd_buffer = NULL;
static int prev_lba = 0x80000000;
static int hits, reads;
#undef dprintf
#define dprintf(...)
void PicoCDBufferInit(void)
{
void *tmp = NULL;
prev_lba = 0x80000000;
hits = reads = 0;
if (PicoCDBuffers <= 1) {
PicoCDBuffers = 0;
return; /* buffering off */
}
/* try alloc'ing until we succeed */
while (PicoCDBuffers > 0)
{
tmp = realloc(cd_buffer, PicoCDBuffers * 2048 + 304);
if (tmp != NULL) break;
PicoCDBuffers >>= 1;
}
if (PicoCDBuffers <= 0) return; /* buffering became off */
cd_buffer = tmp;
}
void PicoCDBufferFree(void)
{
if (cd_buffer) {
free(cd_buffer);
cd_buffer = NULL;
}
if (reads)
elprintf(EL_STATUS, "CD buffer hits: %i/%i (%i%%)\n", hits, reads, hits * 100 / reads);
}
void PicoCDBufferFlush(void)
{
prev_lba = 0x80000000;
}
/* this is was a try to fight slow SD access of GP2X */
PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba)
{
int is_bin, offs, read_len, moved = 0;
reads++;
is_bin = Pico_mcd->TOC.Tracks[0].ftype == TYPE_BIN;
if (PicoCDBuffers <= 0)
{
/* no buffering */
int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F);
return;
}
/* hit? */
offs = lba - prev_lba;
if (offs >= 0 && offs < PicoCDBuffers)
{
hits++;
if (offs == 0) dprintf("CD buffer seek to old %i -> %i\n", prev_lba, lba);
memcpy32(dest, (int *)(cd_buffer + offs*2048), 2048/4);
return;
}
if (prev_lba + PicoCDBuffers != lba)
{
int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
dprintf("CD buffer seek %i -> %i\n", prev_lba, lba);
pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
}
dprintf("CD buffer miss %i -> %i\n", prev_lba, lba);
if (lba < prev_lba && prev_lba - lba < PicoCDBuffers)
{
read_len = prev_lba - lba;
dprintf("CD buffer move=%i, read_len=%i", PicoCDBuffers - read_len, read_len);
memmove(cd_buffer + read_len*2048, cd_buffer, (PicoCDBuffers - read_len)*2048);
moved = 1;
}
else
{
read_len = PicoCDBuffers;
}
if (PicoMessage != NULL && read_len >= 512)
{
PicoMessage("Buffering data...");
}
if (is_bin)
{
int i = 0;
#ifdef _PSP_FW_VERSION
int bufs = (read_len*2048) / (2048+304);
pm_read(cd_buffer, bufs*(2048+304), Pico_mcd->TOC.Tracks[0].F);
for (i = 1; i < bufs; i++)
// should really use memmove here, but my memcpy32 implementation is also suitable here
memcpy32((int *)(cd_buffer + i*2048), (int *)(cd_buffer + i*(2048+304)), 2048/4);
#endif
for (; i < read_len - 1; i++)
{
pm_read(cd_buffer + i*2048, 2048 + 304, Pico_mcd->TOC.Tracks[0].F);
// pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR); // seeking is slower, in PSP case even more
}
// further data might be moved, do not overwrite
pm_read(cd_buffer + i*2048, 2048, Pico_mcd->TOC.Tracks[0].F);
pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR);
}
else
{
pm_read(cd_buffer, read_len*2048, Pico_mcd->TOC.Tracks[0].F);
}
memcpy32(dest, (int *) cd_buffer, 2048/4);
prev_lba = lba;
if (moved)
{
/* file pointer must point to the same data in file, as would-be data after our buffer */
int where_seek;
lba += PicoCDBuffers;
where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
}
}

398
pico/cd/cd_file.c Normal file
View file

@ -0,0 +1,398 @@
/***********************************************************
* *
* This source was taken from the Gens project *
* Written by Stéphane Dallongeville *
* Copyright (c) 2002 by Stéphane Dallongeville *
* Modified/adapted for PicoDrive by notaz, 2007 *
* *
***********************************************************/
#include "../pico_int.h"
#include "cd_file.h"
#include "cue.h"
//#define cdprintf(f,...) printf(f "\n",##__VA_ARGS__) // tmp
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;
}
}
static int audio_track_mp3(const char *fname, int index)
{
_scd_track *Tracks = Pico_mcd->TOC.Tracks;
FILE *tmp_file;
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); // used to calculate length
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
Tracks[index].KBtps = (short) mp3_get_bitrate(tmp_file, fs);
Tracks[index].KBtps >>= 3;
if (ret != 0 || Tracks[index].KBtps <= 0)
{
elprintf(EL_STATUS, "track %2i: mp3 bitrate %i", index+1, Tracks[index].KBtps);
#ifdef _PSP_FW_VERSION
free(tmp_file);
#else
fclose(tmp_file);
#endif
return -1;
}
Tracks[index].F = tmp_file;
// MP3 File
Tracks[index].ftype = TYPE_MP3;
fs *= 75;
fs /= Tracks[index].KBtps * 1000;
Tracks[index].Length = fs;
Tracks[index].Offset = 0;
return 0;
}
PICO_INTERNAL int Load_CD_Image(const char *cd_img_name, cd_img_type type)
{
int i, j, num_track, Cur_LBA, index, ret, iso_name_len, missed, cd_img_sectors;
_scd_track *Tracks = Pico_mcd->TOC.Tracks;
char tmp_name[1024], tmp_ext[10], tmp_ext_u[10];
cue_data_t *cue_data = NULL;
pm_file *pmf;
static const char *exts[] = {
"%02d.mp3", " %02d.mp3", "-%02d.mp3", "_%02d.mp3", " - %02d.mp3",
"%d.mp3", " %d.mp3", "-%d.mp3", "_%d.mp3", " - %d.mp3",
};
if (PicoCDLoadProgressCB != NULL)
PicoCDLoadProgressCB(cd_img_name, 1);
Unload_ISO();
/* is this .cue? */
ret = strlen(cd_img_name);
if (ret >= 3 && strcasecmp(cd_img_name + ret - 3, "cue") == 0)
cue_data = cue_parse(cd_img_name);
if (cue_data != NULL)
cd_img_name = cue_data->tracks[1].fname;
Tracks[0].ftype = type == CIT_BIN ? TYPE_BIN : TYPE_ISO;
Tracks[0].F = pmf = pm_open(cd_img_name);
if (Tracks[0].F == NULL)
{
Tracks[0].ftype = 0;
Tracks[0].Length = 0;
if (cue_data != NULL)
cue_destroy(cue_data);
return -1;
}
if (Tracks[0].ftype == TYPE_ISO)
cd_img_sectors = pmf->size >>= 11; // size in sectors
else cd_img_sectors = pmf->size /= 2352;
Tracks[0].Offset = 0;
Tracks[0].MSF.M = 0; // minutes
Tracks[0].MSF.S = 2; // seconds
Tracks[0].MSF.F = 0; // frames
elprintf(EL_STATUS, "Track 1: %02d:%02d:%02d %9i DATA",
Tracks[0].MSF.M, Tracks[0].MSF.S, Tracks[0].MSF.F, Tracks[0].Length);
Cur_LBA = Tracks[0].Length = cd_img_sectors;
if (cue_data != NULL)
{
if (cue_data->tracks[2].fname == NULL) { // NULL means track2 is in same file as track1
Cur_LBA = Tracks[0].Length = cue_data->tracks[2].sector_offset;
}
i = 100 / cue_data->track_count+1;
for (num_track = 2; num_track <= cue_data->track_count; num_track++)
{
if (PicoCDLoadProgressCB != NULL)
PicoCDLoadProgressCB(cd_img_name, i * num_track);
index = num_track - 1;
Cur_LBA += cue_data->tracks[num_track].pregap;
if (cue_data->tracks[num_track].type == CT_MP3) {
ret = audio_track_mp3(cue_data->tracks[num_track].fname, index);
if (ret != 0) break;
}
else
{
Tracks[index].ftype = cue_data->tracks[num_track].type;
if (cue_data->tracks[num_track].fname != NULL)
{
pm_file *pmfn = pm_open(cue_data->tracks[num_track].fname);
if (pmfn != NULL)
{
// addume raw, ignore header for wav..
Tracks[index].F = pmfn;
Tracks[index].Length = pmfn->size / 2352;
Tracks[index].Offset = cue_data->tracks[num_track].sector_offset;
}
else
{
elprintf(EL_STATUS, "track %2i (%s): can't determine length",
num_track, cue_data->tracks[num_track].fname);
Tracks[index].Length = 2*75;
Tracks[index].Offset = 0;
}
}
else
{
if (num_track < cue_data->track_count)
Tracks[index].Length = cue_data->tracks[num_track+1].sector_offset -
cue_data->tracks[num_track].sector_offset;
else
Tracks[index].Length = cd_img_sectors - cue_data->tracks[num_track].sector_offset;
Tracks[index].Offset = cue_data->tracks[num_track].sector_offset;
}
}
if (cue_data->tracks[num_track].sector_xlength != 0)
// overriden by custom cue command
Tracks[index].Length = cue_data->tracks[num_track].sector_xlength;
LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
Cur_LBA += Tracks[index].Length;
elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", num_track, Tracks[index].MSF.M,
Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length,
cue_data->tracks[num_track].fname);
}
cue_destroy(cue_data);
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 (num_track = 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 = num_track - 1;
sprintf(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 = audio_track_mp3(tmp_name, index);
if (ret != 0) {
strcpy(p, tmp_ext_u);
ret = audio_track_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 = audio_track_mp3(tmp_name, index);
if (ret != 0) {
strcpy(p, tmp_ext_u);
ret = audio_track_mp3(tmp_name, index);
}
}
if (ret == 0)
{
LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
Cur_LBA += Tracks[index].Length;
elprintf(EL_STATUS, "Track %2i: %02d:%02d:%02d %9i AUDIO - %s", num_track, Tracks[index].MSF.M,
Tracks[index].MSF.S, Tracks[index].MSF.F, Tracks[index].Length, tmp_name);
num_track++;
missed = 0;
break;
}
}
if (ret != 0 && i > 1) missed++;
}
finish:
Pico_mcd->TOC.Last_Track = num_track - 1;
index = num_track - 1;
LBA_to_MSF(Cur_LBA, &Tracks[index].MSF);
elprintf(EL_STATUS, "End CD - %02d:%02d:%02d\n", Tracks[index].MSF.M,
Tracks[index].MSF.S, Tracks[index].MSF.F);
if (PicoCDLoadProgressCB != NULL)
PicoCDLoadProgressCB(cd_img_name, 100);
return 0;
}
PICO_INTERNAL void Unload_ISO(void)
{
int i;
if (Pico_mcd == NULL) return;
if (Pico_mcd->TOC.Tracks[0].F) pm_close(Pico_mcd->TOC.Tracks[0].F);
for(i = 1; i < 100; i++)
{
if (Pico_mcd->TOC.Tracks[i].F != NULL)
{
if (Pico_mcd->TOC.Tracks[i].ftype == TYPE_MP3)
#ifdef _PSP_FW_VERSION
free(Pico_mcd->TOC.Tracks[i].F);
#else
fclose(Pico_mcd->TOC.Tracks[i].F);
#endif
else
pm_close(Pico_mcd->TOC.Tracks[i].F);
}
}
memset(Pico_mcd->TOC.Tracks, 0, sizeof(Pico_mcd->TOC.Tracks));
}
PICO_INTERNAL int FILE_Read_One_LBA_CDC(void)
{
if (Pico_mcd->s68k_regs[0x36] & 1) // DATA
{
if (Pico_mcd->TOC.Tracks[0].F == NULL) return -1;
// moved below..
//fseek(Pico_mcd->TOC.Tracks[0].F, where_read, SEEK_SET);
//fread(cp_buf, 1, 2048, Pico_mcd->TOC.Tracks[0].F);
cdprintf("Read file CDC 1 data sector :\n");
}
else // AUDIO
{
cdprintf("Read file CDC 1 audio sector :\n");
}
// Update CDC stuff
CDC_Update_Header();
if (Pico_mcd->s68k_regs[0x36] & 1) // DATA track
{
if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
{
if (Pico_mcd->cdc.CTRL.B.B0 & 0x04) // WRRQ : this bit enable write to buffer
{
int where_read = 0;
// CAUTION : lookahead bit not implemented
if (Pico_mcd->scd.Cur_LBA < 0)
where_read = 0;
else if (Pico_mcd->scd.Cur_LBA >= Pico_mcd->TOC.Tracks[0].Length)
where_read = Pico_mcd->TOC.Tracks[0].Length - 1;
else where_read = Pico_mcd->scd.Cur_LBA;
Pico_mcd->scd.Cur_LBA++;
Pico_mcd->cdc.WA.N = (Pico_mcd->cdc.WA.N + 2352) & 0x7FFF; // add one sector to WA
Pico_mcd->cdc.PT.N = (Pico_mcd->cdc.PT.N + 2352) & 0x7FFF;
*(unsigned int *)(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N) = Pico_mcd->cdc.HEAD.N;
//memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N + 4], cp_buf, 2048);
//pm_seek(Pico_mcd->TOC.Tracks[0].F, where_read, SEEK_SET);
//pm_read(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N + 4, 2048, Pico_mcd->TOC.Tracks[0].F);
PicoCDBufferRead(Pico_mcd->cdc.Buffer + Pico_mcd->cdc.PT.N + 4, where_read);
cdprintf("Read -> WA = %d Buffer[%d] =", Pico_mcd->cdc.WA.N, Pico_mcd->cdc.PT.N & 0x3FFF);
cdprintf("Header 1 = %.2X %.2X %.2X %.2X", Pico_mcd->cdc.HEAD.B.B0,
Pico_mcd->cdc.HEAD.B.B1, Pico_mcd->cdc.HEAD.B.B2, Pico_mcd->cdc.HEAD.B.B3);
cdprintf("Header 2 = %.2X %.2X %.2X %.2X --- %.2X %.2X\n\n",
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 0) & 0x3FFF],
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 1) & 0x3FFF],
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 2) & 0x3FFF],
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 3) & 0x3FFF],
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 4) & 0x3FFF],
Pico_mcd->cdc.Buffer[(Pico_mcd->cdc.PT.N + 5) & 0x3FFF]);
}
}
}
else // music track
{
Pico_mcd->scd.Cur_LBA++;
Pico_mcd->cdc.WA.N = (Pico_mcd->cdc.WA.N + 2352) & 0x7FFF; // add one sector to WA
Pico_mcd->cdc.PT.N = (Pico_mcd->cdc.PT.N + 2352) & 0x7FFF;
if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
{
if (Pico_mcd->cdc.CTRL.B.B0 & 0x04) // WRRQ : this bit enable write to buffer
{
// CAUTION : lookahead bit not implemented
// this is pretty rough, but oh well - not much depends on this anyway
memcpy(&Pico_mcd->cdc.Buffer[Pico_mcd->cdc.PT.N], cdda_out_buffer, 2352);
}
}
}
if (Pico_mcd->cdc.CTRL.B.B0 & 0x80) // DECEN = decoding enable
{
Pico_mcd->cdc.STAT.B.B0 = 0x80;
if (Pico_mcd->cdc.CTRL.B.B0 & 0x10) // determine form bit form sub header ?
{
Pico_mcd->cdc.STAT.B.B2 = Pico_mcd->cdc.CTRL.B.B1 & 0x08;
}
else
{
Pico_mcd->cdc.STAT.B.B2 = Pico_mcd->cdc.CTRL.B.B1 & 0x0C;
}
if (Pico_mcd->cdc.CTRL.B.B0 & 0x02) Pico_mcd->cdc.STAT.B.B3 = 0x20; // ECC done
else Pico_mcd->cdc.STAT.B.B3 = 0x00; // ECC not done
if (Pico_mcd->cdc.IFCTRL & 0x20)
{
if (Pico_mcd->s68k_regs[0x33] & (1<<5))
{
elprintf(EL_INTS, "cdc dec irq 5");
SekInterruptS68k(5);
}
Pico_mcd->cdc.IFSTAT &= ~0x20; // DEC interrupt happen
Pico_mcd->cdc.Decode_Reg_Read = 0; // Reset read after DEC int
}
}
return 0;
}

32
pico/cd/cd_file.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef _CD_FILE_H
#define _CD_FILE_H
#ifdef __cplusplus
extern "C" {
#endif
#define TYPE_ISO 1
#define TYPE_BIN 2
#define TYPE_MP3 3
#define TYPE_WAV 4
typedef enum
{
CIT_NOT_CD = 0,
CIT_ISO,
CIT_BIN,
CIT_CUE
}
cd_img_type;
PICO_INTERNAL int Load_CD_Image(const char *iso_name, cd_img_type type);
PICO_INTERNAL void Unload_ISO(void);
PICO_INTERNAL int FILE_Read_One_LBA_CDC(void);
#ifdef __cplusplus
};
#endif
#endif

View file

@ -1,285 +0,0 @@
/*
* 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 "cd_parse.h"
#if defined(__GNUC__) && __GNUC__ >= 7
#pragma GCC diagnostic ignored "-Wformat-truncation"
#endif
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->type = CT_AUDIO;
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;
}
*d = 0;
}
// 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;
cd_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;
} else {
cue_data = chd_parse(cd_img_name);
if (cue_data != NULL)
*type = cue_data->tracks[1].type;
}
pmf = pm_open(cd_img_name);
if (pmf == NULL)
{
if (cue_data != NULL)
cdparse_destroy(cue_data);
return -1;
}
tracks[0].fd = pmf;
tracks[0].fname = strdup(cd_img_name);
tracks[0].type = *type & CT_AUDIO;
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 %s %s",
tmp_ext, tracks[0].end, tracks[0].type ? "AUDIO" : "DATA ", cd_img_name);
lba = cd_img_sectors;
if (cue_data != NULL)
{
if (cue_data->track_count > 1 && 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].fname = strdup(cue_data->tracks[n].fname);
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].type = cue_data->tracks[n].type & CT_AUDIO;
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 %s %s", n, tmp_ext, length,
tracks[index].type ? "AUDIO" : "DATA ",
cue_data->tracks[n].fname ? 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;
tracks[index].type = CT_AUDIO;
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;
tracks[n].start = cdd.toc.end;
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)
cdparse_destroy(cue_data);
return 0;
}
// vim:shiftwidth=2:ts=2:expandtab

View file

@ -1,477 +0,0 @@
/*
* cuefile handling
* (C) notaz, 2008
* (C) irixxxx, 2020-2023
*
* 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 "../pico_int.h"
#include "cd_parse.h"
// #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
#if defined(USE_LIBCHDR)
#include "libchdr/chd.h"
#include "libchdr/cdrom.h"
#endif
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
#ifdef __EPOC32__
#define snprintf(b,s,...) sprintf(b,##__VA_ARGS__)
#endif
static char *mystrip(char *str)
{
int i, len;
len = strlen(str);
for (i = 0; i < len; i++)
if (str[i] != ' ') break;
if (i > 0) memmove(str, str + i, len - i + 1);
len = strlen(str);
for (i = len - 1; i >= 0; i--)
if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
str[i+1] = 0;
return str;
}
static int get_token(const char *buff, char *dest, int len)
{
const char *p = buff;
char sep = ' ';
int d = 0, skip = 0;
while (*p && *p == ' ') {
skip++;
p++;
}
if (*p == '\"') {
sep = '\"';
p++;
}
while (*p && *p != sep && d < len-1)
dest[d++] = *p++;
dest[d] = 0;
if (sep == '\"' && *p != sep)
elprintf(EL_STATUS, "cue: bad token: \"%s\"", buff);
return d + skip;
}
static int get_ext(const char *fname, char ext[4],
char *base, size_t base_size)
{
size_t pos = 0;
char *p;
ext[0] = 0;
if (!(p = strrchr(fname, '.')))
return -1;
pos = p - fname;
strncpy(ext, fname + pos + 1, 4/*sizeof(ext)*/-1);
ext[4/*sizeof(ext)*/-1] = '\0';
if (base != NULL && base_size > 0) {
if (pos >= base_size)
pos = base_size - 1;
memcpy(base, fname, pos);
base[pos] = 0;
}
return pos;
}
static void change_case(char *p, int to_upper)
{
for (; *p != 0; p++) {
if (to_upper && 'a' <= *p && *p <= 'z')
*p += 'A' - 'a';
else if (!to_upper && 'A' <= *p && *p <= 'Z')
*p += 'a' - 'A';
}
}
static int file_openable(const char *fname)
{
FILE *f = fopen(fname, "rb");
if (f == NULL)
return 0;
fclose(f);
return 1;
}
#define BEGINS(buff,str) (strncmp(buff,str,sizeof(str)-1) == 0)
/* note: tracks[0] is not used */
cd_data_t *chd_parse(const char *fname)
{
cd_data_t *data = NULL;
#if defined(USE_LIBCHDR)
cd_data_t *tmp;
int count = 0, count_alloc = 2;
int sectors = 0;
char metadata[256];
chd_file *cf = NULL;
if (fname == NULL || *fname == '\0')
return NULL;
if (chd_open(fname, CHD_OPEN_READ, NULL, &cf) != CHDERR_NONE)
goto out;
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (data == NULL)
goto out;
// get track info
while (count < CD_MAX_TRACKS) {
int track = 0, frames = 0, pregap = 0, postgap = 0;
char type[16], subtype[16], pgtype[16], pgsub[16];
type[0] = subtype[0] = pgtype[0] = pgsub[0] = 0;
// get metadata for track
if (chd_get_metadata(cf, CDROM_TRACK_METADATA2_TAG, count,
metadata, sizeof(metadata), 0, 0, 0) == CHDERR_NONE) {
if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT,
&track, &type[0], &subtype[0], &frames,
&pregap, &pgtype[0], &pgsub[0], &postgap) != 8)
break;
}
else if (chd_get_metadata(cf, CDROM_TRACK_METADATA_TAG, count,
metadata, sizeof(metadata), 0, 0, 0) == CHDERR_NONE) {
if (sscanf(metadata, CDROM_TRACK_METADATA_FORMAT,
&track, &type[0], &subtype[0], &frames) != 4)
break;
}
else break; // all tracks completed
// metadata sanity check
if (track != count + 1 || frames < 0 || pregap < 0)
break;
// allocate track structure
count ++;
if (count >= count_alloc) {
count_alloc *= 2;
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (tmp == NULL) {
count--;
break;
}
data = tmp;
}
memset(&data->tracks[count], 0, sizeof(data->tracks[0]));
if (count == 1)
data->tracks[count].fname = strdup(fname);
if (!strcmp(type, "MODE1_RAW") || !strcmp(type, "MODE2_RAW")) {
data->tracks[count].type = CT_BIN;
} else if (!strcmp(type, "MODE1") || !strcmp(type, "MODE2_FORM1")) {
data->tracks[count].type = CT_ISO;
} else if (!strcmp(type, "AUDIO")) {
data->tracks[count].type = CT_CHD;
} else
break;
data->tracks[count].pregap = pregap;
if (pgtype[0] != 'V') // VAUDIO includes pregap in file
pregap = 0;
data->tracks[count].sector_offset = sectors + pregap;
data->tracks[count].sector_xlength = frames - pregap;
sectors += (((frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING) * CD_TRACK_PADDING);
}
// check if image id OK, i.e. there are tracks, and length <= 80 min
if (count && sectors < (80*60*75)) {
data->track_count = count;
} else {
free(data);
data = NULL;
}
out:
if (cf)
chd_close(cf);
#endif
return data;
}
cd_data_t *cue_parse(const char *fname)
{
char current_file[256], *current_filep, cue_base[256];
char buff[256], buff2[32], ext[4], *p;
int ret, count = 0, count_alloc = 2, pending_pregap = 0;
size_t current_filep_size, fname_len;
cd_data_t *data = NULL, *tmp;
FILE *f = NULL;
if (fname == NULL || (fname_len = strlen(fname)) == 0)
return NULL;
ret = get_ext(fname, ext, cue_base, sizeof(cue_base) - 4);
if (strcasecmp(ext, "cue") == 0) {
f = fopen(fname, "r");
}
else if (strcasecmp(ext, "chd") != 0) {
// not a .cue, try one with the same base name
if (0 < ret && ret < sizeof(cue_base)) {
strcpy(cue_base + ret, ".cue");
f = fopen(cue_base, "r");
if (f == NULL) {
strcpy(cue_base + ret, ".CUE");
f = fopen(cue_base, "r");
}
}
}
if (f == NULL)
return NULL;
snprintf(current_file, sizeof(current_file), "%s", fname);
current_filep = current_file + strlen(current_file);
for (; current_filep > current_file; current_filep--)
if (current_filep[-1] == '/' || current_filep[-1] == '\\')
break;
current_filep_size = sizeof(current_file) - (current_filep - current_file);
// the basename of cuefile, no path
snprintf(cue_base, sizeof(cue_base), "%s", current_filep);
p = strrchr(cue_base, '.');
if (p) p[1] = '\0';
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (data == NULL)
goto out;
while (!feof(f))
{
if (fgets(buff, sizeof(buff), f) == NULL)
break;
mystrip(buff);
if (buff[0] == 0)
continue;
if (BEGINS(buff, "TITLE ") || BEGINS(buff, "PERFORMER ") || BEGINS(buff, "SONGWRITER "))
continue; /* who would put those here? Ignore! */
else if (BEGINS(buff, "FILE "))
{
get_token(buff + 5, current_filep, current_filep_size);
}
else if (BEGINS(buff, "TRACK "))
{
count++;
if (count >= count_alloc) {
count_alloc *= 2;
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (tmp == NULL) {
count--;
break;
}
data = tmp;
}
memset(&data->tracks[count], 0, sizeof(data->tracks[0]));
if (count == 1 || strcmp(data->tracks[1].fname, current_file) != 0)
{
if (file_openable(current_file))
goto file_ok;
elprintf(EL_STATUS, "cue: bad/missing file: \"%s\"", current_file);
if (count == 1) {
int cue_ucase;
char v;
get_ext(current_file, ext, NULL, 0);
snprintf(current_filep, current_filep_size,
"%s%s", cue_base, ext);
if (file_openable(current_file))
goto file_ok;
// try with the same case (for unix)
v = fname[fname_len - 1];
cue_ucase = ('A' <= v && v <= 'Z');
change_case(ext, cue_ucase);
snprintf(current_filep, current_filep_size,
"%s%s", cue_base, ext);
if (file_openable(current_file))
goto file_ok;
}
count--;
break;
file_ok:
data->tracks[count].fname = strdup(current_file);
if (data->tracks[count].fname == NULL)
break;
}
data->tracks[count].pregap = pending_pregap;
pending_pregap = 0;
// track number
ret = get_token(buff+6, buff2, sizeof(buff2));
if (count != atoi(buff2))
elprintf(EL_STATUS, "cue: track index mismatch: track %i is track %i in cue",
count, atoi(buff2));
// check type
get_token(buff+6+ret, buff2, sizeof(buff2));
if (strcmp(buff2, "MODE1/2352") == 0)
data->tracks[count].type = CT_BIN;
else if (strcmp(buff2, "MODE1/2048") == 0)
data->tracks[count].type = CT_ISO;
else if (strcmp(buff2, "AUDIO") == 0)
{
if (data->tracks[count].fname != NULL)
{
// rely on extension, not type in cue..
get_ext(data->tracks[count].fname, ext, NULL, 0);
if (strcasecmp(ext, "mp3") == 0)
data->tracks[count].type = CT_MP3;
else if (strcasecmp(ext, "wav") == 0)
data->tracks[count].type = CT_WAV;
else if (strcasecmp(ext, "bin") == 0)
data->tracks[count].type = CT_RAW;
else {
elprintf(EL_STATUS, "unhandled audio format: \"%s\"",
data->tracks[count].fname);
}
}
else if (data->tracks[count-1].type & CT_AUDIO)
{
// propagate previous
data->tracks[count].type = data->tracks[count-1].type;
}
else
{
// assume raw binary data
data->tracks[count].type = CT_RAW;
}
}
else {
elprintf(EL_STATUS, "unhandled track type: \"%s\"", buff2);
}
}
else if (BEGINS(buff, "INDEX "))
{
int m, s, f;
// type
ret = get_token(buff+6, buff2, sizeof(buff2));
if (atoi(buff2) == 0) continue;
if (atoi(buff2) != 1) {
elprintf(EL_STATUS, "cue: don't know how to handle: \"%s\"", buff);
count--; break;
}
// offset in file
get_token(buff+6+ret, buff2, sizeof(buff2));
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
if (ret != 3) {
elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
count--; break;
}
data->tracks[count].sector_offset = m*60*75 + s*75 + f;
// some strange .cues may need this
if (data->tracks[count].fname != NULL && strcmp(data->tracks[count].fname, current_file) != 0)
{
free(data->tracks[count].fname);
data->tracks[count].fname = strdup(current_file);
}
if (data->tracks[count].fname == NULL && strcmp(data->tracks[1].fname, current_file) != 0)
{
data->tracks[count].fname = strdup(current_file);
}
}
else if (BEGINS(buff, "PREGAP ") || BEGINS(buff, "POSTGAP "))
{
int m, s, f;
get_token(buff+7, buff2, sizeof(buff2));
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
if (ret != 3) {
elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
continue;
}
// pregap overrides previous postgap?
// by looking at some .cues produced by some programs I've decided that..
if (BEGINS(buff, "PREGAP "))
data->tracks[count].pregap = m*60*75 + s*75 + f;
else
pending_pregap = m*60*75 + s*75 + f;
}
else if (BEGINS(buff, "REM LENGTH ")) // custom "extension"
{
int m, s, f;
get_token(buff+11, buff2, sizeof(buff2));
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
if (ret != 3) continue;
data->tracks[count].sector_xlength = m*60*75 + s*75 + f;
}
else if (BEGINS(buff, "REM"))
continue;
else
{
elprintf(EL_STATUS, "cue: unhandled line: \"%s\"", buff);
}
}
if (count < 1 || data->tracks[1].fname == NULL) {
// failed..
for (; count > 0; count--)
if (data->tracks[count].fname != NULL)
free(data->tracks[count].fname);
free(data);
data = NULL;
goto out;
}
data->track_count = count;
out:
if (f != NULL)
fclose(f);
return data;
}
void cdparse_destroy(cd_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);
}
#if 0
int main(int argc, char *argv[])
{
cd_data_t *data = cue_parse(argv[1]);
int c;
if (data == NULL) return 1;
for (c = 1; c <= data->track_count; c++)
printf("%2i: %i %9i %02i:%02i:%02i %9i %s\n", c, data->tracks[c].type, data->tracks[c].sector_offset,
data->tracks[c].sector_offset / (75*60), data->tracks[c].sector_offset / 75 % 60,
data->tracks[c].sector_offset % 75, data->tracks[c].pregap, data->tracks[c].fname);
cdparse_destroy(data);
return 0;
}
#endif

View file

@ -1,5 +0,0 @@
cd_data_t *chd_parse(const char *fname);
cd_data_t *cue_parse(const char *fname);
void cdparse_destroy(cd_data_t *data);

742
pico/cd/cd_sys.c Normal file
View file

@ -0,0 +1,742 @@
/***********************************************************
* *
* This source file was taken from the Gens project *
* Written by Stéphane Dallongeville *
* Copyright (c) 2002 by Stéphane Dallongeville *
* Modified/adapted for PicoDrive by notaz, 2007 *
* *
***********************************************************/
#include <stdio.h>
#include "../pico_int.h"
#include "cd_sys.h"
#include "cd_file.h"
#define DEBUG_CD
#define TRAY_OPEN 0x0500 // TRAY OPEN CDD status
#define NOCD 0x0000 // CD removed CDD status
#define STOPPED 0x0900 // STOPPED CDD status (happen after stop or close tray command)
#define READY 0x0400 // READY CDD status (also used for seeking)
#define FAST_FOW 0x0300 // FAST FORWARD track CDD status
#define FAST_REV 0x10300 // FAST REVERSE track CDD status
#define PLAYING 0x0100 // PLAYING audio track CDD status
static int CD_Present = 0;
#define CHECK_TRAY_OPEN \
if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) \
{ \
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \
\
Pico_mcd->cdd.Minute = 0; \
Pico_mcd->cdd.Seconde = 0; \
Pico_mcd->cdd.Frame = 0; \
Pico_mcd->cdd.Ext = 0; \
\
Pico_mcd->scd.CDD_Complete = 1; \
\
return 2; \
}
#define CHECK_CD_PRESENT \
if (!CD_Present) \
{ \
Pico_mcd->scd.Status_CDD = NOCD; \
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD; \
\
Pico_mcd->cdd.Minute = 0; \
Pico_mcd->cdd.Seconde = 0; \
Pico_mcd->cdd.Frame = 0; \
Pico_mcd->cdd.Ext = 0; \
\
Pico_mcd->scd.CDD_Complete = 1; \
\
return 3; \
}
static int MSF_to_LBA(_msf *MSF)
{
return (MSF->M * 60 * 75) + (MSF->S * 75) + MSF->F - 150;
}
PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF)
{
if (lba < -150) lba = 0;
else lba += 150;
MSF->M = lba / (60 * 75);
MSF->S = (lba / 75) % 60;
MSF->F = lba % 75;
}
static unsigned int MSF_to_Track(_msf *MSF)
{
int i, Start, Cur;
Start = (MSF->M << 16) + (MSF->S << 8) + MSF->F;
for(i = 1; i <= (Pico_mcd->TOC.Last_Track + 1); i++)
{
Cur = Pico_mcd->TOC.Tracks[i - 1].MSF.M << 16;
Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.S << 8;
Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.F;
if (Cur > Start) break;
}
--i;
if (i > Pico_mcd->TOC.Last_Track) return 100;
else if (i < 1) i = 1;
return (unsigned) i;
}
static unsigned int LBA_to_Track(int lba)
{
_msf MSF;
LBA_to_MSF(lba, &MSF);
return MSF_to_Track(&MSF);
}
static void Track_to_MSF(int track, _msf *MSF)
{
if (track < 1) track = 1;
else if (track > Pico_mcd->TOC.Last_Track) track = Pico_mcd->TOC.Last_Track;
MSF->M = Pico_mcd->TOC.Tracks[track - 1].MSF.M;
MSF->S = Pico_mcd->TOC.Tracks[track - 1].MSF.S;
MSF->F = Pico_mcd->TOC.Tracks[track - 1].MSF.F;
}
PICO_INTERNAL int Track_to_LBA(int track)
{
_msf MSF;
Track_to_MSF(track, &MSF);
return MSF_to_LBA(&MSF);
}
PICO_INTERNAL void Check_CD_Command(void)
{
cdprintf("CHECK CD COMMAND");
// Check CDC
if (Pico_mcd->scd.Status_CDC & 1) // CDC is reading data ...
{
cdprintf("Got a read command");
// DATA ?
if (Pico_mcd->scd.Cur_Track == 1)
Pico_mcd->s68k_regs[0x36] |= 0x01;
else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
if (Pico_mcd->scd.File_Add_Delay == 0)
{
FILE_Read_One_LBA_CDC();
}
else Pico_mcd->scd.File_Add_Delay--;
}
// Check CDD
if (Pico_mcd->scd.CDD_Complete)
{
Pico_mcd->scd.CDD_Complete = 0;
CDD_Export_Status();
}
if (Pico_mcd->scd.Status_CDD == FAST_FOW)
{
Pico_mcd->scd.Cur_LBA += 10;
CDC_Update_Header();
}
else if (Pico_mcd->scd.Status_CDD == FAST_REV)
{
Pico_mcd->scd.Cur_LBA -= 10;
if (Pico_mcd->scd.Cur_LBA < -150) Pico_mcd->scd.Cur_LBA = -150;
CDC_Update_Header();
}
}
PICO_INTERNAL int Init_CD_Driver(void)
{
return 0;
}
PICO_INTERNAL void End_CD_Driver(void)
{
Unload_ISO();
}
PICO_INTERNAL void Reset_CD(void)
{
Pico_mcd->scd.Cur_Track = 0;
Pico_mcd->scd.Cur_LBA = -150;
Pico_mcd->scd.Status_CDC &= ~1;
Pico_mcd->scd.Status_CDD = CD_Present ? READY : NOCD;
Pico_mcd->scd.CDD_Complete = 0;
Pico_mcd->scd.File_Add_Delay = 0;
}
int Insert_CD(const char *cdimg_name, int type)
{
int ret = 1;
CD_Present = 0;
Pico_mcd->scd.Status_CDD = NOCD;
if (cdimg_name != NULL && type != CIT_NOT_CD)
{
ret = Load_CD_Image(cdimg_name, type);
if (ret == 0) {
CD_Present = 1;
/* for open tray close command will handle Status_CDD */
if (Pico_mcd->scd.Status_CDD != TRAY_OPEN)
Pico_mcd->scd.Status_CDD = READY;
}
}
return ret;
}
void Stop_CD(void)
{
Unload_ISO();
CD_Present = 0;
}
/*
PICO_INTERNAL void Change_CD(void)
{
if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) Close_Tray_CDD_cC();
else Open_Tray_CDD_cD();
}
*/
PICO_INTERNAL int Get_Status_CDD_c0(void)
{
cdprintf("Status command : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);
// Clear immediat status
if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0200)
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0700)
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0E00)
Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Stop_CDD_c1(void)
{
CHECK_TRAY_OPEN
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
if (CD_Present) Pico_mcd->scd.Status_CDD = STOPPED;
else Pico_mcd->scd.Status_CDD = NOCD;
Pico_mcd->cdd.Status = 0x0000;
Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped
Pico_mcd->cdd.Minute = 0;
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Get_Pos_CDD_c20(void)
{
_msf MSF;
cdprintf("command 200 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);
CHECK_TRAY_OPEN
Pico_mcd->cdd.Status &= 0xFF;
if (!CD_Present)
{
Pico_mcd->scd.Status_CDD = NOCD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
}
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
cdprintf("Status CDD = %.4X Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);
LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);
Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);
Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);
Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Get_Track_Pos_CDD_c21(void)
{
int elapsed_time;
_msf MSF;
cdprintf("command 201 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);
CHECK_TRAY_OPEN
Pico_mcd->cdd.Status &= 0xFF;
if (!CD_Present)
{
Pico_mcd->scd.Status_CDD = NOCD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
}
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
elapsed_time = Pico_mcd->scd.Cur_LBA - Track_to_LBA(LBA_to_Track(Pico_mcd->scd.Cur_LBA));
LBA_to_MSF(elapsed_time - 150, &MSF);
cdprintf(" elapsed = %d", elapsed_time);
Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);
Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);
Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Get_Current_Track_CDD_c22(void)
{
cdprintf("Status CDD = %.4X Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);
CHECK_TRAY_OPEN
Pico_mcd->cdd.Status &= 0xFF;
if (!CD_Present)
{
Pico_mcd->scd.Status_CDD = NOCD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
}
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void)
{
CHECK_TRAY_OPEN
Pico_mcd->cdd.Status &= 0xFF;
if (!CD_Present)
{
Pico_mcd->scd.Status_CDD = NOCD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
}
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.M);
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.S);
Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.F);
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void)
{
CHECK_TRAY_OPEN
Pico_mcd->cdd.Status &= 0xFF;
if (!CD_Present)
{
Pico_mcd->scd.Status_CDD = NOCD;
}
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Minute = INT_TO_BCDW(1);
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Last_Track);
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Get_Track_Adr_CDD_c25(void)
{
int track_number;
CHECK_TRAY_OPEN
// track number in TC4 & TC5
track_number = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
Pico_mcd->cdd.Status &= 0xFF;
if (!CD_Present)
{
Pico_mcd->scd.Status_CDD = NOCD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
}
// else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;
if (track_number > Pico_mcd->TOC.Last_Track) track_number = Pico_mcd->TOC.Last_Track;
else if (track_number < 1) track_number = 1;
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.M);
Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.S);
Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.F);
Pico_mcd->cdd.Ext = track_number % 10;
if (track_number == 1) Pico_mcd->cdd.Frame |= 0x0800; // data track
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Play_CDD_c3(void)
{
_msf MSF;
int delay, new_lba;
CHECK_TRAY_OPEN
CHECK_CD_PRESENT
// MSF of the track to play in TC buffer
MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);
MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);
Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);
new_lba = MSF_to_LBA(&MSF);
delay = new_lba - Pico_mcd->scd.Cur_LBA;
if (delay < 0) delay = -delay;
delay >>= 12;
// based on genplys GX
if (delay < 13)
delay = 13;
Pico_mcd->scd.Cur_LBA = new_lba;
CDC_Update_Header();
cdprintf("Read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);
if (Pico_mcd->scd.Status_CDD != PLAYING) delay += 20;
Pico_mcd->scd.Status_CDD = PLAYING;
Pico_mcd->cdd.Status = 0x0102;
// Pico_mcd->cdd.Status = COMM_OK;
if (Pico_mcd->scd.File_Add_Delay == 0) Pico_mcd->scd.File_Add_Delay = delay;
if (Pico_mcd->scd.Cur_Track == 1)
{
Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA
}
else
{
Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
cdda_start_play();
}
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Seek_CDD_c4(void)
{
_msf MSF;
CHECK_TRAY_OPEN
CHECK_CD_PRESENT
// MSF to seek in TC buffer
MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);
MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);
MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);
Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);
Pico_mcd->scd.Cur_LBA = MSF_to_LBA(&MSF);
CDC_Update_Header();
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
Pico_mcd->scd.Status_CDD = READY;
Pico_mcd->cdd.Status = 0x0200;
// DATA ?
if (Pico_mcd->scd.Cur_Track == 1)
Pico_mcd->s68k_regs[0x36] |= 0x01;
else Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
Pico_mcd->cdd.Minute = 0;
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Pause_CDD_c6(void)
{
CHECK_TRAY_OPEN
CHECK_CD_PRESENT
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read to start a new one if raw data
Pico_mcd->scd.Status_CDD = READY;
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
Pico_mcd->s68k_regs[0x36] |= 0x01; // Data bit set because stopped
Pico_mcd->cdd.Minute = 0;
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Resume_CDD_c7(void)
{
CHECK_TRAY_OPEN
CHECK_CD_PRESENT
Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);
#ifdef DEBUG_CD
{
_msf MSF;
LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);
cdprintf("Resume read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);
}
#endif
Pico_mcd->scd.Status_CDD = PLAYING;
Pico_mcd->cdd.Status = 0x0102;
if (Pico_mcd->scd.Cur_Track == 1)
{
Pico_mcd->s68k_regs[0x36] |= 0x01; // DATA
}
else
{
Pico_mcd->s68k_regs[0x36] &= ~0x01; // AUDIO
cdda_start_play();
}
if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;
else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.Status_CDC |= 1; // Read data with CDC
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Fast_Foward_CDD_c8(void)
{
CHECK_TRAY_OPEN
CHECK_CD_PRESENT
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
Pico_mcd->scd.Status_CDD = FAST_FOW;
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Fast_Rewind_CDD_c9(void)
{
CHECK_TRAY_OPEN
CHECK_CD_PRESENT
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
Pico_mcd->scd.Status_CDD = FAST_REV;
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;
Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Close_Tray_CDD_cC(void)
{
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
elprintf(EL_STATUS, "tray close\n");
if (PicoMCDcloseTray != NULL)
PicoMCDcloseTray();
Pico_mcd->scd.Status_CDD = CD_Present ? STOPPED : NOCD;
Pico_mcd->cdd.Status = 0x0000;
Pico_mcd->cdd.Minute = 0;
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int Open_Tray_CDD_cD(void)
{
CHECK_TRAY_OPEN
Pico_mcd->scd.Status_CDC &= ~1; // Stop CDC read
elprintf(EL_STATUS, "tray open\n");
Unload_ISO();
CD_Present = 0;
if (PicoMCDopenTray != NULL)
PicoMCDopenTray();
Pico_mcd->scd.Status_CDD = TRAY_OPEN;
Pico_mcd->cdd.Status = 0x0E00;
Pico_mcd->cdd.Minute = 0;
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int CDD_cA(void)
{
CHECK_TRAY_OPEN
CHECK_CD_PRESENT
Pico_mcd->scd.Status_CDC &= ~1;
Pico_mcd->scd.Status_CDD = READY;
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Minute = 0;
Pico_mcd->cdd.Seconde = INT_TO_BCDW(1);
Pico_mcd->cdd.Frame = INT_TO_BCDW(1);
Pico_mcd->cdd.Ext = 0;
Pico_mcd->scd.CDD_Complete = 1;
return 0;
}
PICO_INTERNAL int CDD_Def(void)
{
Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;
Pico_mcd->cdd.Minute = 0;
Pico_mcd->cdd.Seconde = 0;
Pico_mcd->cdd.Frame = 0;
Pico_mcd->cdd.Ext = 0;
return 0;
}

111
pico/cd/cd_sys.h Normal file
View file

@ -0,0 +1,111 @@
/***********************************************************
* *
* This source was taken from the Gens project *
* Written by Stéphane Dallongeville *
* Copyright (c) 2002 by Stéphane Dallongeville *
* Modified/adapted for PicoDrive by notaz, 2007 *
* *
***********************************************************/
#ifndef _CD_SYS_H
#define _CD_SYS_H
#include "cd_file.h"
#ifdef __cplusplus
extern "C" {
#endif
#define INT_TO_BCDB(c) \
((c) > 99)?(0x99):((((c) / 10) << 4) + ((c) % 10));
#define INT_TO_BCDW(c) \
((c) > 99)?(0x0909):((((c) / 10) << 8) + ((c) % 10));
#define BCDB_TO_INT(c) \
(((c) >> 4) * 10) + ((c) & 0xF);
#define BCDW_TO_INT(c) \
(((c) >> 8) * 10) + ((c) & 0xF);
typedef struct
{
unsigned char M;
unsigned char S;
unsigned char F;
} _msf;
typedef struct
{
// unsigned char Type; // always 1 (data) for 1st track, 0 (audio) for others
// unsigned char Num; // unused
_msf MSF;
//
char ftype; // TYPE_ISO, TYPE_BIN, TYPE_MP3
void *F;
int Length;
int Offset; // sector offset, when single file is used for multiple virtual tracks
short KBtps; // kbytes per sec for mp3s (bitrate / 1000 / 8)
short pad;
} _scd_track;
typedef struct
{
// unsigned char First_Track; // always 1
_scd_track Tracks[100];
unsigned int Last_Track;
} _scd_toc;
typedef struct {
unsigned int Status_CDD;
unsigned int Status_CDC;
int Cur_LBA;
unsigned int Cur_Track;
int File_Add_Delay;
char CDD_Complete;
int pad[6];
} _scd;
PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF);
PICO_INTERNAL int Track_to_LBA(int track);
// moved to pico.h
// int Insert_CD(char *iso_name, int is_bin);
// void Stop_CD(void);
PICO_INTERNAL void Check_CD_Command(void);
PICO_INTERNAL int Init_CD_Driver(void);
PICO_INTERNAL void End_CD_Driver(void);
PICO_INTERNAL void Reset_CD(void);
PICO_INTERNAL int Get_Status_CDD_c0(void);
PICO_INTERNAL int Stop_CDD_c1(void);
PICO_INTERNAL int Get_Pos_CDD_c20(void);
PICO_INTERNAL int Get_Track_Pos_CDD_c21(void);
PICO_INTERNAL int Get_Current_Track_CDD_c22(void);
PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void);
PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void);
PICO_INTERNAL int Get_Track_Adr_CDD_c25(void);
PICO_INTERNAL int Play_CDD_c3(void);
PICO_INTERNAL int Seek_CDD_c4(void);
PICO_INTERNAL int Pause_CDD_c6(void);
PICO_INTERNAL int Resume_CDD_c7(void);
PICO_INTERNAL int Fast_Foward_CDD_c8(void);
PICO_INTERNAL int Fast_Rewind_CDD_c9(void);
PICO_INTERNAL int CDD_cA(void);
PICO_INTERNAL int Close_Tray_CDD_cC(void);
PICO_INTERNAL int Open_Tray_CDD_cD(void);
PICO_INTERNAL int CDD_Def(void);
#ifdef __cplusplus
};
#endif
#endif

View file

@ -1,870 +0,0 @@
/***************************************************************************************
* 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
#define DMA_CYCLES_PER_BYTE 4 // or 6?
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 bytes_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 bytes = bytes_in;
int words = bytes_in >> 1;
int dst_limit = 0;
uint8 *dst;
int len;
elprintf(EL_CD, "dma %d %04x->%04x %x",
type, cdc.dac, dst_addr, bytes_in);
switch (type)
{
case pcm_ram_dma_w:
dst_addr = (dst_addr << 2) & 0xffc;
if (dst_addr + bytes > 0x1000) {
elprintf(EL_ANOMALY, "pcm dma oflow: %x %x", dst_addr, words);
bytes = 0x1000 - dst_addr;
}
dst = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank];
dst = dst + dst_addr;
while (bytes > 0)
{
if (src_addr + bytes > 0x4000) {
len = 0x4000 - src_addr;
memcpy(dst, cdc.ram + src_addr, len);
dst += len;
src_addr = 0;
bytes -= len;
continue;
}
memcpy(dst, cdc.ram + src_addr, bytes);
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;
}
bytes_in &= ~1; // Todo leftover byte?
update_dma:
/* update DMA addresses */
cdc.dac += bytes_in;
if (type == pcm_ram_dma_w)
dma_addr += bytes_in >> 2;
else
dma_addr += bytes_in >> 3;
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);
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
cdc.dbc = 0xffff;
/* clear !DTEN and !DTBSY */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
/* clear DSR bit & set EDT bit (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0x80;
if (cdc.ifstat & BIT_DTEI) {
/* 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");
pcd_irq_s68k(5, 1);
}
}
}
/* 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;
/* set CRCOK bit */
cdc.stat[0] = BIT_DECEN;
/* 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");
pcd_irq_s68k(5, 1);
}
}
/* 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] & 0x1F)
{
case 0x00:
break;
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");
pcd_irq_s68k(5, 1);
}
}
else // if (scd.pending & (1 << 5))
{
/* clear pending level 5 interrupts */
pcd_irq_s68k(5, 0);
}
/* 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 & 0x0f) << 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 * DMA_CYCLES_PER_BYTE);
}
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 */
pcd_irq_s68k(5, 0);
}
#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 */
{
/* reset DECI if decoder turned off */
if (!(data & BIT_DECEN))
cdc.ifstat |= BIT_DECI;
/* 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 */
Pico_mcd->s68k_regs[0x04+1] = (Pico_mcd->s68k_regs[0x04+1] + 1) & 0x1f;
break;
}
}
unsigned char cdc_reg_r(void)
{
switch (Pico_mcd->s68k_regs[0x04+1] & 0x1F)
{
case 0x00:
return 0xff;
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 */
pcd_irq_s68k(5, 0);
}
#endif
Pico_mcd->s68k_regs[0x04+1] = 0x10;
return data;
}
default: /* by default, COMIN is always empty */
Pico_mcd->s68k_regs[0x04+1] = (Pico_mcd->s68k_regs[0x04+1] + 1) & 0x1f;
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 = 0xffff;
/* clear !DTEN and !DTBSY */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
/* clear DSR bit & set EDT bit (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0x80;
} else if ((int16)cdc.dbc <= 2)
{
if (cdc.ifstat & BIT_DTEI) {
/* 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");
pcd_irq_s68k(5, 1);
}
}
}
/* set DSR and EDT bit (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0xc0;
}
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

@ -1,100 +0,0 @@
/***************************************************************************************
* 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
{
int type;
char *fname;
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

275
pico/cd/cue.c Normal file
View file

@ -0,0 +1,275 @@
/*
* 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
static char *mystrip(char *str)
{
int i, len;
len = strlen(str);
for (i = 0; i < len; i++)
if (str[i] != ' ') break;
if (i > 0) memmove(str, str + i, len - i + 1);
len = strlen(str);
for (i = len - 1; i >= 0; i--)
if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n') break;
str[i+1] = 0;
return str;
}
static int get_token(const char *buff, char *dest, int len)
{
const char *p = buff;
char sep = ' ';
int d = 0, skip = 0;
while (*p && *p == ' ') {
skip++;
p++;
}
if (*p == '\"') {
sep = '\"';
p++;
}
while (*p && *p != sep && d < len-1)
dest[d++] = *p++;
dest[d] = 0;
if (sep == '\"' && *p != sep)
elprintf(EL_STATUS, "cue: bad token: \"%s\"", buff);
return d + skip;
}
static char *get_ext(char *fname)
{
int len = strlen(fname);
return (len >= 3) ? (fname + len - 3) : fname;
}
#define BEGINS(buff,str) (strncmp(buff,str,sizeof(str)-1) == 0)
/* note: tracks[0] is not used */
cue_data_t *cue_parse(const char *fname)
{
char buff[256], current_file[256], buff2[32], *current_filep;
FILE *f, *tmpf;
int ret, count = 0, count_alloc = 2, pending_pregap = 0;
cue_data_t *data;
void *tmp;
f = fopen(fname, "r");
if (f == NULL) return NULL;
snprintf(current_file, sizeof(current_file), "%s", fname);
for (current_filep = current_file + strlen(current_file); current_filep > current_file; current_filep--)
if (current_filep[-1] == '/' || current_filep[-1] == '\\') break;
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cue_track));
if (data == NULL) {
fclose(f);
return NULL;
}
while (!feof(f))
{
tmp = fgets(buff, sizeof(buff), f);
if (tmp == NULL) break;
mystrip(buff);
if (buff[0] == 0) continue;
if (BEGINS(buff, "TITLE ") || BEGINS(buff, "PERFORMER ") || BEGINS(buff, "SONGWRITER "))
continue; /* who would put those here? Ignore! */
else if (BEGINS(buff, "FILE "))
{
get_token(buff+5, current_filep, sizeof(current_file) - (current_filep - current_file));
}
else if (BEGINS(buff, "TRACK "))
{
count++;
if (count >= count_alloc) {
count_alloc *= 2;
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cue_track));
if (tmp == NULL) { count--; break; }
data = tmp;
}
memset(&data->tracks[count], 0, sizeof(data->tracks[0]));
if (count == 1 || strcmp(data->tracks[1].fname, current_file) != 0)
{
data->tracks[count].fname = strdup(current_file);
if (data->tracks[count].fname == NULL) break;
tmpf = fopen(current_file, "rb");
if (tmpf == NULL) {
elprintf(EL_STATUS, "cue: bad/missing file: \"%s\"", current_file);
count--; break;
}
fclose(tmpf);
}
data->tracks[count].pregap = pending_pregap;
pending_pregap = 0;
// track number
ret = get_token(buff+6, buff2, sizeof(buff2));
if (count != atoi(buff2))
elprintf(EL_STATUS, "cue: track index mismatch: track %i is track %i in cue",
count, atoi(buff2));
// check type
get_token(buff+6+ret, buff2, sizeof(buff2));
if (strcmp(buff2, "MODE1/2352") == 0)
data->tracks[count].type = CT_BIN;
else if (strcmp(buff2, "MODE1/2048") == 0)
data->tracks[count].type = CT_ISO;
else if (strcmp(buff2, "AUDIO") == 0)
{
if (data->tracks[count].fname != NULL)
{
// rely on extension, not type in cue..
char *ext = get_ext(data->tracks[count].fname);
if (strcasecmp(ext, "mp3") == 0)
data->tracks[count].type = CT_MP3;
else if (strcasecmp(ext, "wav") == 0)
data->tracks[count].type = CT_WAV;
else {
elprintf(EL_STATUS, "unhandled audio format: \"%s\"",
data->tracks[count].fname);
}
}
else
{
// propagate previous
data->tracks[count].type = data->tracks[count-1].type;
}
}
else {
elprintf(EL_STATUS, "unhandled track type: \"%s\"", buff2);
}
}
else if (BEGINS(buff, "INDEX "))
{
int m, s, f;
// type
ret = get_token(buff+6, buff2, sizeof(buff2));
if (atoi(buff2) == 0) continue;
if (atoi(buff2) != 1) {
elprintf(EL_STATUS, "cue: don't know how to handle: \"%s\"", buff);
count--; break;
}
// offset in file
get_token(buff+6+ret, buff2, sizeof(buff2));
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
if (ret != 3) {
elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
count--; break;
}
data->tracks[count].sector_offset = m*60*75 + s*75 + f;
// some strange .cues may need this
if (data->tracks[count].fname != NULL && strcmp(data->tracks[count].fname, current_file) != 0)
{
free(data->tracks[count].fname);
data->tracks[count].fname = strdup(current_file);
}
if (data->tracks[count].fname == NULL && strcmp(data->tracks[1].fname, current_file) != 0)
{
data->tracks[count].fname = strdup(current_file);
}
}
else if (BEGINS(buff, "PREGAP ") || BEGINS(buff, "POSTGAP "))
{
int m, s, f;
get_token(buff+7, buff2, sizeof(buff2));
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
if (ret != 3) {
elprintf(EL_STATUS, "cue: failed to parse: \"%s\"", buff);
continue;
}
// pregap overrides previous postgap?
// by looking at some .cues produced by some programs I've decided that..
if (BEGINS(buff, "PREGAP "))
data->tracks[count].pregap = m*60*75 + s*75 + f;
else
pending_pregap = m*60*75 + s*75 + f;
}
else if (BEGINS(buff, "REM LENGTH ")) // custom "extension"
{
int m, s, f;
get_token(buff+11, buff2, sizeof(buff2));
ret = sscanf(buff2, "%d:%d:%d", &m, &s, &f);
if (ret != 3) continue;
data->tracks[count].sector_xlength = m*60*75 + s*75 + f;
}
else if (BEGINS(buff, "REM"))
continue;
else
{
elprintf(EL_STATUS, "cue: unhandled line: \"%s\"", buff);
}
}
if (count < 1 || data->tracks[1].fname == NULL) {
// failed..
for (; count > 0; count--)
if (data->tracks[count].fname != NULL)
free(data->tracks[count].fname);
free(data);
return NULL;
}
data->track_count = count;
return data;
}
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);
}
#if 0
int main(int argc, char *argv[])
{
cue_data_t *data = cue_parse(argv[1]);
int c;
if (data == NULL) return 1;
for (c = 1; c <= data->track_count; c++)
printf("%2i: %i %9i %02i:%02i:%02i %9i %s\n", c, data->tracks[c].type, data->tracks[c].sector_offset,
data->tracks[c].sector_offset / (75*60), data->tracks[c].sector_offset / 75 % 60,
data->tracks[c].sector_offset % 75, data->tracks[c].pregap, data->tracks[c].fname);
cue_destroy(data);
return 0;
}
#endif

29
pico/cd/cue.h Normal file
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

@ -1,24 +0,0 @@
#undef uint8
#undef uint16
#undef uint32
#undef int8
#undef int16
#undef int32
#define uint8 u8
#define uint16 u16
#define uint32 u32
#define int8 s8
#define int16 s16
#define int32 s32
#define READ_BYTE(BASE, ADDR) (BASE)[MEM_BE2(ADDR)]
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[MEM_BE2(ADDR)] = (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

@ -1,487 +0,0 @@
/***************************************************************************************
* 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 */
uint32 stampMask; /* stamp number 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 */
uint16 lut_cell2[0x80]; /* Graphics operation stamp offset lookup table */
uint16 lut_cell4[0x80]; /* 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 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 = yyxxhrr (7 bits) */
/* with: yy = cell row (0-3) */
/* xx = cell column (0-3) */
/* hrr = HFLIP & ROTATION bits */
for (i=0; i<0x80; i++)
{
/* one stamp = 2x2 cells (16x16) or 4x4 cells (32x32) */
row = (i >> 5) & 3;
col = (i >> 3) & 3;
if (i & 4) { col = col ^ 3; } /* HFLIP (always first) */
if (i & 2) { col = col ^ 3; row = row ^ 3; } /* ROLL1 */
if (i & 1) { temp = col; col = row ^ 3; row = temp; } /* ROLL0 */
/* cell offset (0-3 or 0-15) */
gfx.lut_cell2[i] = ((row&1) + (col&1) * 2) << 6;
gfx.lut_cell4[i] = ((row&3) + (col&3) * 4) << 6;
}
/* 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 inline int gfx_pixel(uint32 xpos, uint32 ypos, uint16 *lut_cell)
{
uint16 stamp_data;
uint32 stamp_index;
uint8 pixel_out = 0x00;
/* check if pixel is outside stamp map */
if (((xpos | ypos) & ~gfx.dotMask) == 0)
{
/* 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 & gfx.stampMask) << 8;
if (stamp_index)
{
/* extract HFLIP & ROTATION bits */
stamp_data = (stamp_data >> 13) & 7;
/* cell offset (0-3 or 0-15) */
/* table entry = yyxxhrr (7 bits) */
/* with: yy = cell row (0-3) = (ypos >> (11 + 3)) & 3 */
/* xx = cell column (0-3) = (xpos >> (11 + 3)) & 3 */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= lut_cell[stamp_data | ((ypos >> 9) & 0x60) | ((xpos >> 11) & 0x18)];
/* 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 | ((ypos >> 5) & 0x1c0) | ((xpos >> 8) & 0x38)];
/* read pixel pair (2 pixels/byte) */
pixel_out = READ_BYTE(Pico_mcd->word_ram2M, stamp_index >> 1);
/* extract left or right pixel */
pixel_out >>= 4 * !(stamp_index & 1);
pixel_out &= 0x0f;
}
}
return pixel_out;
}
#define RENDER_LOOP(N, UPDP, COND1, COND2) do { \
if (bufferIndex & 1) { \
bufferIndex ^= 1; \
goto right##N; /* no initial left pixel */ \
} \
/* process all dots */ \
while (width--) \
{ \
/* left pixel */ \
xpos &= mask; \
ypos &= mask; \
\
if (COND1) { \
pixel_out = gfx_pixel(xpos, ypos, lut_cell); \
UPDP; \
} \
\
if (COND2) { \
/* read out paired pixel data */ \
pixel_in = READ_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1); \
\
/* priority mode write */ \
pixel_in = (lut_prio[(pixel_in & 0xf0) >> 4][pixel_out] << 4) | \
(pixel_in & 0x0f); \
\
/* write data to image buffer */ \
WRITE_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1, pixel_in); \
} \
\
/* increment pixel position */ \
xpos += xoffset; \
ypos += yoffset; \
\
right##N: \
if (width-- == 0) break; \
\
/* right pixel */ \
xpos &= mask; \
ypos &= mask; \
\
if (COND1) { \
pixel_out = gfx_pixel(xpos, ypos, lut_cell); \
UPDP; \
} \
\
if (COND2) { \
/* read out paired pixel data */ \
pixel_in = READ_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1); \
\
/* priority mode write */ \
pixel_in = (lut_prio[pixel_in & 0x0f][pixel_out]) | \
(pixel_in & 0xf0); \
\
/* write data to image buffer */ \
WRITE_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1, pixel_in); \
} \
\
/* increment pixel position */ \
xpos += xoffset; \
ypos += yoffset; \
\
/* next pixel */ \
bufferIndex += 2; \
/* check current pixel position */ \
if ((bufferIndex & 7) == 0) \
{ \
/* next cell: increment buffer offset by one column (minus 8 pixels) */ \
bufferIndex += gfx.bufferOffset-1; \
} \
} \
} while (0)
static void gfx_render(uint32 bufferIndex, uint32 width)
{
uint8 pixel_in, pixel_out;
uint32 priority;
uint8 (*lut_prio)[0x10];
uint16 *lut_cell;
uint32 mask;
/* 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;
lut_prio = gfx.lut_prio[priority];
lut_cell = (Pico_mcd->s68k_regs[0x58+1] & 0x02) ? gfx.lut_cell4 : gfx.lut_cell2;
/* check if stamp map is repeated */
mask = 0xffffff; /* 24-bit range */
if (Pico_mcd->s68k_regs[0x58+1] & 0x01)
{
/* stamp map range */
mask = gfx.dotMask;
}
pixel_out = 0;
if (xoffset+(1U<<10) <= 1U<<11 && yoffset+(1U<<10) <= 1U<<11) {
/* upscaling >= 2x, test for duplicate pixels to avoid recalculation */
uint32 oldx, oldy;
oldx = oldy = ~xpos;
RENDER_LOOP(1, oldx = xpos;oldy = ypos, (oldx^xpos ^ oldy^ypos) >> 11, (!priority) | pixel_out);
} else {
RENDER_LOOP(3, , 1, (!priority) | pixel_out);
}
}
void gfx_start(uint32 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.stampMask = 0x7ff; /* 16x16 dots/stamp */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamp */
gfx.mapShift = 4; /* 16x16 stamps/map */
mask = 0x3fe00; /* 512 bytes/table */
break;
case 1:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampMask = 0x7fc; /* 16x16 dots/stamp */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamp */
gfx.mapShift = 3; /* 8x8 stamps/map */
mask = 0x3ff80; /* 128 bytes/table */
break;
case 2:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampMask = 0x7ff; /* 16x16 dots/stamp */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamp */
gfx.mapShift = 8; /* 256x256 stamps/map */
mask = 0x20000; /* 131072 bytes/table */
break;
case 3:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampMask = 0x7fc; /* 16x16 dots/stamp */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamp */
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;
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
Pico_mcd->m.s68k_poll_cnt = 0;
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;
y_step = h;
if (cycles > UPDATE_CYCLES)
y_step = (UPDATE_CYCLES + 5 * w - 1) / (5 * w);
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;
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
Pico_mcd->m.s68k_poll_cnt = 0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
elprintf(EL_INTS|EL_CD, "s68k: gfx_cd irq 1");
pcd_irq_s68k(1, 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 (PicoIn.opt & 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

424
pico/cd/gfx_cd.c Normal file
View file

@ -0,0 +1,424 @@
// This is a direct rewrite of gfx_cd.asm (x86 asm to C).
// You can even find some x86 register names :)
// Original code (c) 2002 by Stéphane Dallongeville
// (c) Copyright 2007, Grazvydas "notaz" Ignotas
#include "../pico_int.h"
#undef dprintf
#define dprintf(...)
#define _rot_comp Pico_mcd->rot_comp
static void gfx_do_line(unsigned int func, unsigned short *stamp_base,
unsigned int H_Dot);
static void gfx_cd_start(void)
{
int w, h;
w = _rot_comp.Reg_62;
h = _rot_comp.Reg_64;
if (w == 0 || h == 0) {
elprintf(EL_CD|EL_ANOMALY, "gfx_cd_start with %ux%u", w, h);
_rot_comp.Reg_64 = 0;
// irq?
return;
}
// _rot_comp.XD_Mul = ((_rot_comp.Reg_5C & 0x1f) + 1) * 4; // unused
_rot_comp.Function = (_rot_comp.Reg_58 & 7) | (Pico_mcd->s68k_regs[3] & 0x18); // Jmp_Adr
// _rot_comp.Buffer_Adr = (_rot_comp.Reg_5E & 0xfff8) << 2; // unused?
_rot_comp.YD = (_rot_comp.Reg_60 >> 3) & 7;
_rot_comp.Vector_Adr = (_rot_comp.Reg_66 & 0xfffe) << 2;
_rot_comp.Reg_58 |= 0x8000; // Stamp_Size, we start a new GFX operation
pcd_event_schedule_s68k(PCD_EVENT_GFX, 5 * w * h);
switch (_rot_comp.Reg_58 & 6) // Scr_16?
{
case 0: // ?
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xff80) << 2;
break;
case 2: // .Dot_32
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xffe0) << 2;
break;
case 4: // .Scr_16
_rot_comp.Stamp_Map_Adr = 0x20000;
break;
case 6: // .Scr_16_Dot_32
_rot_comp.Stamp_Map_Adr = (_rot_comp.Reg_5A & 0xe000) << 2;
break;
}
if (PicoOpt & POPT_EN_MCD_GFX)
{
unsigned int func = _rot_comp.Function;
unsigned short *stamp_base = (unsigned short *) (Pico_mcd->word_ram2M + _rot_comp.Stamp_Map_Adr);
while (h--)
gfx_do_line(func, stamp_base, w);
}
}
PICO_INTERNAL_ASM unsigned int gfx_cd_read(unsigned int a)
{
unsigned int d = 0;
switch (a) {
case 0x58: d = _rot_comp.Reg_58; break;
case 0x5A: d = _rot_comp.Reg_5A; break;
case 0x5C: d = _rot_comp.Reg_5C; break;
case 0x5E: d = _rot_comp.Reg_5E; break;
case 0x60: d = _rot_comp.Reg_60; break;
case 0x62: d = _rot_comp.Reg_62; break;
case 0x64:
d = _rot_comp.Reg_64;
if (_rot_comp.Reg_64 > 1)
// fudge..
_rot_comp.Reg_64--;
break;
case 0x66: break;
default: dprintf("gfx_cd_read FIXME: unexpected address: %02x", a); break;
}
dprintf("gfx_cd_read(%02x) = %04x", a, d);
return d;
}
static void gfx_do_line(unsigned int func, unsigned short *stamp_base,
unsigned int H_Dot)
{
unsigned int eax, ebx, ecx, edx, esi, edi, pixel;
unsigned int XD, Buffer_Adr;
int DYXS;
XD = _rot_comp.Reg_60 & 7;
Buffer_Adr = ((_rot_comp.Reg_5E & 0xfff8) + _rot_comp.YD) << 2;
ecx = *(unsigned int *)(Pico_mcd->word_ram2M + _rot_comp.Vector_Adr);
edx = ecx >> 16;
ecx = (ecx & 0xffff) << 8;
edx <<= 8;
DYXS = *(int *)(Pico_mcd->word_ram2M + _rot_comp.Vector_Adr + 4);
_rot_comp.Vector_Adr += 8;
// MAKE_IMAGE_LINE
while (H_Dot)
{
// MAKE_IMAGE_PIXEL
if (!(func & 1)) // NOT TILED
{
int mask = (func & 4) ? 0x00800000 : 0x00f80000;
if ((ecx | edx) & mask)
{
if (func & 0x18) goto Next_Pixel;
pixel = 0;
goto Pixel_Out;
}
}
if (func & 2) // mode 32x32 dot
{
if (func & 4) // 16x16 screen
{
ebx = ((ecx >> (11+5)) & 0x007f) |
((edx >> (11-2)) & 0x3f80);
}
else // 1x1 screen
{
ebx = ((ecx >> (11+5)) & 0x07) |
((edx >> (11+2)) & 0x38);
}
}
else // mode 16x16 dot
{
if (func & 4) // 16x16 screen
{
ebx = ((ecx >> (11+4)) & 0x00ff) |
((edx >> (11-4)) & 0xff00);
}
else // 1x1 screen
{
ebx = ((ecx >> (11+4)) & 0x0f) |
((edx >> (11+0)) & 0xf0);
}
}
edi = stamp_base[ebx];
esi = (edi & 0x7ff) << 7;
if (!esi) { pixel = 0; goto Pixel_Out; }
edi >>= (11+1);
edi &= (0x1c>>1);
eax = ecx;
ebx = edx;
if (func & 2) edi |= 1; // 32 dots?
switch (edi)
{
case 0x00: // No_Flip_0, 16x16 dots
ebx = (ebx >> 9) & 0x3c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x1000; // bswap
eax = ((eax >> 8) & 0x40) + ebx;
break;
case 0x01: // No_Flip_0, 32x32 dots
ebx = (ebx >> 9) & 0x7c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x1000; // bswap
eax = ((eax >> 7) & 0x180) + ebx;
break;
case 0x02: // No_Flip_90, 16x16 dots
eax = (eax >> 9) & 0x3c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x2800; // bswap
eax += ((ebx >> 8) & 0x40) ^ 0x40;
break;
case 0x03: // No_Flip_90, 32x32 dots
eax = (eax >> 9) & 0x7c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x2800; // bswap
eax += ((ebx >> 7) & 0x180) ^ 0x180;
break;
case 0x04: // No_Flip_180, 16x16 dots
ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x2800; // bswap and flip
eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
break;
case 0x05: // No_Flip_180, 32x32 dots
ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x2800; // bswap and flip
eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
break;
case 0x06: // No_Flip_270, 16x16 dots
eax = ((eax >> 9) & 0x3c) ^ 0x3c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x1000; // bswap
eax += (ebx >> 8) & 0x40;
break;
case 0x07: // No_Flip_270, 32x32 dots
eax = ((eax >> 9) & 0x7c) ^ 0x7c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x1000; // bswap
eax += (ebx >> 7) & 0x180;
break;
case 0x08: // Flip_0, 16x16 dots
ebx = (ebx >> 9) & 0x3c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x2800; // bswap, flip
eax = (((eax >> 8) & 0x40) ^ 0x40) + ebx;
break;
case 0x09: // Flip_0, 32x32 dots
ebx = (ebx >> 9) & 0x7c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x2800; // bswap, flip
eax = (((eax >> 7) & 0x180) ^ 0x180) + ebx;
break;
case 0x0a: // Flip_90, 16x16 dots
eax = ((eax >> 9) & 0x3c) ^ 0x3c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x2800; // bswap, flip
eax += ((ebx >> 8) & 0x40) ^ 0x40;
break;
case 0x0b: // Flip_90, 32x32 dots
eax = ((eax >> 9) & 0x7c) ^ 0x7c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x2800; // bswap, flip
eax += ((ebx >> 7) & 0x180) ^ 0x180;
break;
case 0x0c: // Flip_180, 16x16 dots
ebx = ((ebx >> 9) & 0x3c) ^ 0x3c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x1000; // bswap
eax = ((eax >> 8) & 0x40) + ebx;
break;
case 0x0d: // Flip_180, 32x32 dots
ebx = ((ebx >> 9) & 0x7c) ^ 0x7c;
ebx += esi;
edi = (eax & 0x3800) ^ 0x1000; // bswap
eax = ((eax >> 7) & 0x180) + ebx;
break;
case 0x0e: // Flip_270, 16x16 dots
eax = (eax >> 9) & 0x3c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x1000; // bswap, flip
eax += (ebx >> 8) & 0x40;
break;
case 0x0f: // Flip_270, 32x32 dots
eax = (eax >> 9) & 0x7c;
eax += esi;
edi = (ebx & 0x3800) ^ 0x1000; // bswap, flip
eax += (ebx >> 7) & 0x180;
break;
}
pixel = *(Pico_mcd->word_ram2M + (edi >> 12) + eax);
if (!(edi & 0x800)) pixel >>= 4;
else pixel &= 0x0f;
Pixel_Out:
if (!pixel && (func & 0x18)) goto Next_Pixel;
esi = Buffer_Adr + ((XD>>1)^1); // pixel addr
eax = *(Pico_mcd->word_ram2M + esi); // old pixel
if (XD & 1)
{
if ((eax & 0x0f) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
*(Pico_mcd->word_ram2M + esi) = pixel | (eax & 0xf0);
}
else
{
if ((eax & 0xf0) && (func & 0x18) == 0x08) goto Next_Pixel; // underwrite
*(Pico_mcd->word_ram2M + esi) = (pixel << 4) | (eax & 0xf);
}
Next_Pixel:
ecx += (DYXS << 16) >> 16; // _rot_comp.DXS;
edx += DYXS >> 16; // _rot_comp.DYS;
XD++;
if (XD >= 8)
{
Buffer_Adr += ((_rot_comp.Reg_5C & 0x1f) + 1) << 5;
XD = 0;
}
H_Dot--;
}
// end while
// nothing_to_draw:
_rot_comp.YD++;
// _rot_comp.V_Dot--; // will be done by caller
}
PICO_INTERNAL_ASM void gfx_cd_write16(unsigned int a, unsigned int d)
{
dprintf("gfx_cd_write16(%x, %04x)", a, d);
if (_rot_comp.Reg_58 & 0x8000)
elprintf(EL_CD|EL_ANOMALY, "cd: busy gfx reg write %02x %04x", a, d);
switch (a) {
case 0x58: // .Reg_Stamp_Size
_rot_comp.Reg_58 = d & 7;
return;
case 0x5A: // .Reg_Stamp_Adr
_rot_comp.Reg_5A = d & 0xffe0;
return;
case 0x5C: // .Reg_IM_VCell_Size
_rot_comp.Reg_5C = d & 0x1f;
return;
case 0x5E: // .Reg_IM_Adr
_rot_comp.Reg_5E = d & 0xFFF8;
return;
case 0x60: // .Reg_IM_Offset
_rot_comp.Reg_60 = d & 0x3f;
return;
case 0x62: // .Reg_IM_HDot_Size
_rot_comp.Reg_62 = d & 0x1ff;
return;
case 0x64: // .Reg_IM_VDot_Size
_rot_comp.Reg_64 = d & 0xff; // V_Dot, must be 32bit?
return;
case 0x66: // .Reg_Vector_Adr
_rot_comp.Reg_66 = d & 0xfffe;
if (Pico_mcd->s68k_regs[3]&4) return; // can't do tanformations in 1M mode
gfx_cd_start();
return;
default: dprintf("gfx_cd_write16 FIXME: unexpected address: %02x", a); return;
}
}
PICO_INTERNAL void gfx_cd_reset(void)
{
memset(&_rot_comp.Reg_58, 0, sizeof(_rot_comp));
}
// --------------------------------
#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;
}

35
pico/cd/gfx_cd.h Normal file
View file

@ -0,0 +1,35 @@
#ifndef _GFX_CD_H
#define _GFX_CD_H
typedef struct
{
unsigned int Reg_58; // Stamp_Size
unsigned int Reg_5A;
unsigned int Reg_5C;
unsigned int Reg_5E;
unsigned int Reg_60;
unsigned int Reg_62;
unsigned int Reg_64; // V_Dot
unsigned int Reg_66;
unsigned int Stamp_Map_Adr;
unsigned int Vector_Adr;
unsigned int Function; // Jmp_Adr;
unsigned int Float_Part;
unsigned int Draw_Speed;
unsigned int YD;
int pad[10];
} Rot_Comp;
PICO_INTERNAL_ASM unsigned int gfx_cd_read(unsigned int a);
PICO_INTERNAL_ASM void gfx_cd_write16(unsigned int a, unsigned int d);
PICO_INTERNAL void gfx_cd_reset(void);
PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc);
#endif // _GFX_CD_H

View file

@ -1,74 +0,0 @@
/*
* 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"
// check: Heart of the alien, jaguar xj 220
PICO_INTERNAL void DmaSlowCell(u32 source, u32 a, int len, unsigned char inc)
{
unsigned char *base;
u32 asrc, a2;
u16 *r;
base = Pico_mcd->word_ram1M[Pico_mcd->s68k_regs[3]&1];
switch (Pico.video.type)
{
case 1: // vram
r = PicoMem.vram;
for(; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
// if(a&1) d=(d<<8)|(d>>8); // ??
VideoWriteVRAM(a, *(u16 *)(base + asrc));
source += 2;
// AutoIncrement
a=(u16)(a+inc);
}
break;
case 3: // cram
Pico.m.dirtyPal = 1;
r = PicoMem.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 = PicoMem.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;
}

@ -1 +0,0 @@
Subproject commit e62ac5995b1c7ef65ece35293914843b8ee57d49

View file

@ -1,7 +1,6 @@
/*
* PicoDrive
* (C) notaz, 2007,2013
* (C) irixxxx, 2019-2024
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
@ -12,35 +11,26 @@
extern unsigned char formatted_bram[4*0x10];
static unsigned int mcd_m68k_cycle_mult;
static unsigned int mcd_s68k_cycle_mult;
static unsigned int mcd_m68k_cycle_base;
static unsigned int mcd_s68k_cycle_base;
static unsigned int m68k_cycle_mult;
void (*PicoMCDopenTray)(void) = NULL;
void (*PicoMCDcloseTray)(void) = NULL;
mcd_state *Pico_mcd;
PICO_INTERNAL void PicoInitMCD(void)
{
SekInitS68k();
Init_CD_Driver();
}
PICO_INTERNAL void PicoExitMCD(void)
{
cdd_unload();
if (Pico_mcd) {
plat_munmap(Pico_mcd, sizeof(mcd_state));
Pico_mcd = NULL;
}
End_CD_Driver();
}
PICO_INTERNAL void PicoPowerMCD(void)
{
int fmt_size;
SekResetS68k();
SekCycleCntS68k = SekCycleAimS68k = 0;
fmt_size = sizeof(formatted_bram);
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));
@ -51,55 +41,42 @@ PICO_INTERNAL void PicoPowerMCD(void)
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
if (Pico.romsize <= 0x20000) // hack to detect BIOS, no GA HINT vector for MSU
memset(Pico.rom + 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_mcd->s68k_regs[6] = 0xff;
Pico_mcd->s68k_regs[7] = 0xff;
memset(Pico_mcd->bios + 0x70, 0xff, 4);
}
PICO_INTERNAL int PicoResetMCD(void)
{
// reset button doesn't affect MCD hardware
// ??
Reset_CD();
LC89510_Reset();
gfx_cd_reset();
#ifdef _ASM_CD_MEMORY_C
//PicoMemResetCDdecode(1); // don't have to call this in 2M mode
#endif
// use Pico.sv.data for RAM cart
if (PicoIn.opt & POPT_EN_MCD_RAMCART) {
if (Pico.sv.data == NULL)
Pico.sv.data = calloc(1, 0x12000);
// use SRam.data for RAM cart
if (PicoOpt & POPT_EN_MCD_RAMCART) {
if (SRam.data == NULL)
SRam.data = calloc(1, 0x12000);
}
else if (Pico.sv.data != NULL) {
free(Pico.sv.data);
Pico.sv.data = NULL;
else if (SRam.data != NULL) {
free(SRam.data);
SRam.data = NULL;
}
Pico.sv.start = Pico.sv.end = 0; // unused
SRam.start = SRam.end = 0; // unused
pcd_event_schedule(0, PCD_EVENT_CDC, 12500000/75);
return 0;
}
static void SekRunS68k(unsigned int to)
static __inline void SekRunS68k(unsigned int to)
{
int cyc_do;
@ -107,7 +84,6 @@ static void SekRunS68k(unsigned int to)
if ((cyc_do = SekCycleAimS68k - SekCycleCntS68k) <= 0)
return;
pprof_start(s68k);
SekCycleCntS68k += cyc_do;
#if defined(EMU_C68K)
PicoCpuCS68k.cycles = cyc_do;
@ -118,44 +94,23 @@ static void SekRunS68k(unsigned int to)
SekCycleCntS68k += m68k_execute(cyc_do) - cyc_do;
m68k_set_context(&PicoCpuMM68k);
#elif defined(EMU_F68K)
SekCycleCntS68k += fm68k_emulate(&PicoCpuFS68k, cyc_do, 0) - cyc_do;
g_m68kcontext = &PicoCpuFS68k;
SekCycleCntS68k += fm68k_emulate(cyc_do, 0, 0) - cyc_do;
g_m68kcontext = &PicoCpuFM68k;
#endif
SekCyclesLeftS68k = 0;
pprof_end(s68k);
}
void PicoMCDPrepare(void)
{
// ~1.63 for NTSC, ~1.645 for PAL
#define DIV_ROUND(x,y) ((x)+(y)/2) / (y) // round to nearest, x/y+0.5 -> (x+y/2)/y
unsigned int osc = (Pico.m.pal ? OSC_PAL : OSC_NTSC);
mcd_m68k_cycle_mult = DIV_ROUND(12500000ull << 16, osc / 7);
mcd_s68k_cycle_mult = DIV_ROUND(1ull * osc << 16, 7 * 12500000);
}
unsigned int pcd_cycles_m68k_to_s68k(unsigned int c)
{
return (long long)c * mcd_m68k_cycle_mult >> 16;
return (long long)c * 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) && (Pico_mcd->s68k_regs[0x37] & 4)) {
elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
pcd_irq_s68k(4, 1);
}
}
Check_CD_Command();
pcd_event_schedule(now, PCD_EVENT_CDC, 12500000/75);
}
@ -163,17 +118,31 @@ 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");
pcd_irq_s68k(3, 1);
SekInterruptS68k(3);
}
if (Pico_mcd->s68k_regs[0x31] != 0)
pcd_event_schedule(now, PCD_EVENT_TIMER3,
(Pico_mcd->s68k_regs[0x31]+1) * 384);
Pico_mcd->s68k_regs[0x31] * 384);
}
static void pcd_gfx_event(unsigned int now)
{
// update gfx chip
if (Pico_mcd->rot_comp.Reg_58 & 0x8000) {
Pico_mcd->rot_comp.Reg_58 &= 0x7fff;
Pico_mcd->rot_comp.Reg_64 = 0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
elprintf(EL_INTS |EL_CD, "s68k: gfx_cd irq 1");
SekInterruptS68k(1);
}
}
}
static void pcd_dma_event(unsigned int now)
{
cdc_dma_update();
int ddx = Pico_mcd->s68k_regs[4] & 7;
Update_CDC_TRansfer(ddx);
}
typedef void (event_cb)(unsigned int now);
@ -182,23 +151,23 @@ typedef void (event_cb)(unsigned int now);
unsigned int pcd_event_times[PCD_EVENT_COUNT];
static unsigned int event_time_next;
static event_cb *pcd_event_cbs[PCD_EVENT_COUNT] = {
pcd_cdc_event, // PCD_EVENT_CDC
pcd_int3_timer_event, // PCD_EVENT_TIMER3
gfx_update, // PCD_EVENT_GFX
pcd_dma_event, // PCD_EVENT_DMA
[PCD_EVENT_CDC] = pcd_cdc_event,
[PCD_EVENT_TIMER3] = pcd_int3_timer_event,
[PCD_EVENT_GFX] = pcd_gfx_event,
[PCD_EVENT_DMA] = pcd_dma_event,
};
void pcd_event_schedule(unsigned int now, enum pcd_event event, int after)
{
unsigned int when;
if ((now|after) == 0) {
when = now + after;
if (when == 0) {
// event cancelled
pcd_event_times[event] = 0;
return;
}
when = now + after;
when |= 1;
elprintf(EL_CD, "cd: new event #%u %u->%u", event, now, when);
@ -210,7 +179,8 @@ void pcd_event_schedule(unsigned int now, enum pcd_event event, int after)
void pcd_event_schedule_s68k(enum pcd_event event, int after)
{
SekEndRunS68k(after);
if (SekCyclesLeftS68k > after)
SekEndRunS68k(after);
pcd_event_schedule(SekCyclesDoneS68k(), event, after);
}
@ -254,32 +224,19 @@ static void pcd_run_events(unsigned int until)
oldest, event_time_next);
}
void pcd_irq_s68k(int irq, int state)
{
if (state) {
SekInterruptS68k(irq);
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
Pico_mcd->m.s68k_poll_cnt = 0;
} else
SekInterruptClearS68k(irq);
}
int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
{
#define now SekCycleCntS68k
unsigned int s68k_target;
unsigned int s68k_target =
(unsigned long long)m68k_target * m68k_cycle_mult >> 16;
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(s68k_target);
pcd_run_events(m68k_target);
return 0;
}
@ -291,11 +248,7 @@ int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
if (Pico_mcd->m.state_flags & (PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP))
SekCycleCntS68k = SekCycleAimS68k = target;
else
SekRunS68k(target);
SekRunS68k(target);
if (m68k_poll_sync && Pico_mcd->m.m68k_poll_cnt == 0)
break;
}
@ -307,61 +260,33 @@ int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
#define pcd_run_cpus_normal pcd_run_cpus
//#define pcd_run_cpus_lockstep pcd_run_cpus
static void SekAimM68k(int cyc, int mult);
static int SekSyncM68k(int once);
static void SekSyncM68k(void);
void pcd_run_cpus_normal(int m68k_cycles)
static inline void pcd_run_cpus_normal(int m68k_cycles)
{
// TODO this is suspicious. ~1 cycle refresh delay every 256 cycles?
SekAimM68k(m68k_cycles, 0x42); // Fhey area
while (CYCLES_GT(Pico.t.m68c_aim, Pico.t.m68c_cnt)) {
if (SekShouldInterrupt()) {
Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;
Pico_mcd->m.m68k_poll_cnt = 0;
}
#ifdef USE_POLL_DETECT
if (Pico_mcd->m.state_flags & PCD_ST_M68K_POLL) {
int s68k_left;
// main CPU is polling, (wake and) run sub only
if (Pico_mcd->m.state_flags & (PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP)) {
Pico_mcd->m.state_flags &= ~(PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP);
Pico_mcd->m.s68k_poll_cnt = 0;
}
s68k_left = pcd_sync_s68k(Pico.t.m68c_aim, 1);
Pico.t.m68c_cnt = Pico.t.m68c_aim;
if (s68k_left > 0)
Pico.t.m68c_cnt -= ((long long)s68k_left * mcd_s68k_cycle_mult >> 16);
if (Pico_mcd->m.state_flags & (PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP)) {
// slave has stopped, wake master to avoid lockups
Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;
Pico_mcd->m.m68k_poll_cnt = 0;
}
SekCycleAim += m68k_cycles;
if (Pico_mcd->m.m68k_poll_cnt >= 16 && !SekShouldInterrupt()) {
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);
} else
#endif
SekSyncM68k(1);
if (Pico_mcd->m.state_flags & PCD_ST_S68K_SYNC) {
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_SYNC;
pcd_sync_s68k(Pico.t.m68c_cnt, 0);
SekCycleCnt = SekCycleAim;
return;
}
SekCycleCnt = SekCycleAim - (s68k_left * 40220 >> 16);
}
SekSyncM68k();
}
void pcd_run_cpus_lockstep(int m68k_cycles)
static inline void pcd_run_cpus_lockstep(int m68k_cycles)
{
unsigned int target = Pico.t.m68c_aim + m68k_cycles;
unsigned int target = SekCycleAim + m68k_cycles;
do {
Pico.t.m68c_aim += 8;
SekSyncM68k(0);
pcd_sync_s68k(Pico.t.m68c_aim, 0);
} while (CYCLES_GT(target, Pico.t.m68c_aim));
Pico.t.m68c_aim = target;
SekCycleAim += 8;
SekSyncM68k();
pcd_sync_s68k(SekCycleAim, 0);
} while (CYCLES_GT(target, SekCycleAim));
}
#define PICO_CD
@ -371,19 +296,17 @@ void pcd_run_cpus_lockstep(int m68k_cycles)
#include "../pico_cmn.c"
void pcd_prepare_frame(void)
{
// need this because we can't have direct mapping between
// master<->slave cycle counters because of overflows
mcd_m68k_cycle_base = Pico.t.m68c_aim;
mcd_s68k_cycle_base = SekCycleAimS68k;
}
PICO_INTERNAL void PicoFrameMCD(void)
{
PicoFrameStart();
if (!(PicoOpt&POPT_ALT_RENDERER))
PicoFrameStart();
// ~1.63 for NTSC, ~1.645 for PAL
if (Pico.m.pal)
m68k_cycle_mult = ((12500000ull << 16) / (50*312*488));
else
m68k_cycle_mult = ((12500000ull << 16) / (60*262*488)) + 1;
pcd_prepare_frame();
PicoFrameHints();
}
@ -394,14 +317,10 @@ void pcd_state_loaded(void)
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(Pico.t.m68c_aim);
if (CYCLES_GE(cycles - SekCycleAimS68k, 1000)) {
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) {
@ -410,20 +329,16 @@ void pcd_state_loaded(void)
if (Pico_mcd->s68k_regs[0x31])
pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_TIMER3,
Pico_mcd->s68k_regs[0x31] * 384);
if (Pico_mcd->rot_comp.Reg_58 & 0x8000) {
Pico_mcd->rot_comp.Reg_58 &= 0x7fff;
Pico_mcd->rot_comp.Reg_64 = 0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1)
SekInterruptS68k(1);
}
if (Pico_mcd->scd.Status_CDC & 0x08)
Update_CDC_TRansfer(Pico_mcd->s68k_regs[4] & 7);
}
diff = cycles - Pico_mcd->pcm.update_cycles;
if ((unsigned int)diff > 12500000/50)
Pico_mcd->pcm.update_cycles = cycles;
if (Pico_mcd->m.need_sync) {
Pico_mcd->m.state_flags |= PCD_ST_S68K_SYNC;
Pico_mcd->m.need_sync = 0;
}
// reschedule
event_time_next = 0;
pcd_run_events(SekCycleCntS68k);
}
// vim:shiftwidth=2:ts=2:expandtab

185
pico/cd/mcd_arm.s Normal file
View file

@ -0,0 +1,185 @@
@*
@* CPU scheduling code
@* (C) notaz, 2007-2008
@*
@* This work is licensed under the terms of MAME license.
@* See COPYING file in the top-level directory.
@*
@ SekRunPS runs PicoCpuCM68k and PicoCpuCS68k interleaved in steps of PS_STEP_M68K
@ cycles. This is done without calling CycloneRun and jumping directly to
@ Cyclone code to avoid pushing/popping all the registers every time.
.equiv PS_STEP_M68K, ((488<<16)/20) @ ~24
@ .extern is ignored by gas, we add these here just to see what we depend on.
.extern CycloneJumpTab
.extern CycloneDoInterrupt
.extern PicoCpuCM68k
.extern PicoCpuCS68k
.extern SekCycleAim
.extern SekCycleCnt
.extern SekCycleAimS68k
.extern SekCycleCntS68k
.text
.align 4
.global SekRunPS @ cyc_m68k, cyc_s68k
SekRunPS:
stmfd sp!, {r4-r8,r10,r11,lr}
sub sp, sp, #2*4 @ sp[0] = main_cycle_cnt, sp[4] = run_cycle_cnt
@ override CycloneEnd for both contexts
ldr r7, =PicoCpuCM68k
ldr lr, =PicoCpuCS68k
ldr r2, =CycloneEnd_M68k
ldr r3, =CycloneEnd_S68k
str r2, [r7,#0x98]
str r3, [lr,#0x98]
@ update aims
ldr r8, =SekCycleAim
ldr r10,=SekCycleAimS68k
ldr r2, [r8]
ldr r3, [r10]
add r2, r2, r0
add r3, r3, r1
str r2, [r8]
str r3, [r10]
ldr r6, =CycloneJumpTab
ldr r1, =SekCycleCnt
ldr r0, =((488<<16)-PS_STEP_M68K)
str r6, [r7,#0x54]
str r6, [lr,#0x54] @ make copies to avoid literal pools
@ schedule m68k for the first time..
ldr r1, [r1]
str r0, [sp] @ main target 'left cycle' counter
sub r1, r2, r1
subs r5, r1, r0, asr #16
ble schedule_s68k @ m68k has not enough cycles
str r5, [sp,#4] @ run_cycle_cnt
b CycloneRunLocal
CycloneEnd_M68k:
ldr r3, =SekCycleCnt
ldr r0, [sp,#4] @ run_cycle_cnt
ldr r1, [r3]
str r4, [r7,#0x40] ;@ Save Current PC + Memory Base
strb r10,[r7,#0x46] ;@ Save Flags (NZCV)
sub r0, r0, r5 @ subtract leftover cycles (which should be negative)
add r0, r0, r1
str r0, [r3]
schedule_s68k:
ldr r8, =SekCycleCntS68k
ldr r10,=SekCycleAimS68k
ldr r3, [sp]
ldr r8, [r8]
ldr r10,[r10]
sub r0, r10, r8
mov r2, r3
add r3, r3, r2, asr #1
add r3, r3, r2, asr #3 @ cycn_s68k = (cycn + cycn/2 + cycn/8)
subs r5, r0, r3, asr #16
ble schedule_m68k @ s68k has not enough cycles
ldr r7, =PicoCpuCS68k
str r5, [sp,#4] @ run_cycle_cnt
b CycloneRunLocal
CycloneEnd_S68k:
ldr r3, =SekCycleCntS68k
ldr r0, [sp,#4] @ run_cycle_cnt
ldr r1, [r3]
str r4, [r7,#0x40] ;@ Save Current PC + Memory Base
strb r10,[r7,#0x46] ;@ Save Flags (NZCV)
sub r0, r0, r5 @ subtract leftover cycles (should be negative)
add r0, r0, r1
str r0, [r3]
schedule_m68k:
ldr r1, =PS_STEP_M68K
ldr r3, [sp] @ main_cycle_cnt
ldr r8, =SekCycleCnt
ldr r10,=SekCycleAim
subs r3, r3, r1
bmi SekRunPS_end
ldr r8, [r8]
ldr r10,[r10]
str r3, [sp] @ update main_cycle_cnt
sub r0, r10, r8
subs r5, r0, r3, asr #16
ble schedule_s68k @ m68k has not enough cycles
ldr r7, =PicoCpuCM68k
str r5, [sp,#4] @ run_cycle_cnt
b CycloneRunLocal
SekRunPS_end:
ldr r7, =PicoCpuCM68k
ldr lr, =PicoCpuCS68k
mov r0, #0
str r0, [r7,#0x98] @ remove CycloneEnd handler
str r0, [lr,#0x98]
@ return
add sp, sp, #2*4
ldmfd sp!, {r4-r8,r10,r11,pc}
CycloneRunLocal:
;@ r0-3 = Temporary registers
ldr r4,[r7,#0x40] ;@ r4 = Current PC + Memory Base
;@ r5 = Cycles
;@ r6 = Opcode Jump table
;@ r7 = Pointer to Cpu Context
;@ r8 = Current Opcode
ldrb r10,[r7,#0x46];@ r10 = Flags (NZCV)
ldr r1,[r7,#0x44] ;@ get SR high and IRQ level
orr r10,r10,r10,lsl #28 ;@ r10 = Flags 0xf0000000, cpsr format
;@ CheckInterrupt:
movs r0,r1,lsr #24 ;@ Get IRQ level
beq NoIntsLocal
cmp r0,#6 ;@ irq>6 ?
andle r1,r1,#7 ;@ Get interrupt mask
cmple r0,r1 ;@ irq<=6: Is irq<=mask ?
bgt CycloneDoInterrupt
NoIntsLocal:
;@ Check if our processor is in special state
;@ and jump to opcode handler if not
ldr r0,[r7,#0x58] ;@ state_flags
ldrh r8,[r4],#2 ;@ Fetch first opcode
tst r0,#0x03 ;@ special state?
andeq r10,r10,#0xf0000000
ldreq pc,[r6,r8,asl #2] ;@ Jump to opcode handler
CycloneSpecial2:
tst r0,#2 ;@ tracing?
bne CycloneDoTrace
;@ stopped or halted
sub r4,r4,#2
ldr r1,[r7,#0x98]
mov r5,#0
bx r1
@ vim:filetype=armasm

File diff suppressed because it is too large Load diff

View file

@ -6,18 +6,15 @@
@* See COPYING file in the top-level directory.
@*
#include <pico/arm_features.h>
#include <pico/pico_int_offs.h>
.equiv PCM_STEP_SHIFT, 11
.text
.align 2
.global PicoRead8_mcd_io
.global PicoRead16_mcd_io
.global PicoWrite8_mcd_io
.global PicoWrite16_mcd_io
.global PicoReadM68k8_io
.global PicoReadM68k16_io
.global PicoWriteM68k8_io
.global PicoWriteM68k16_io
.global PicoReadS68k8_pr
.global PicoReadS68k16_pr
@ -51,22 +48,21 @@
.global PicoWriteS68k16_dec_m2b1
@ externs, just for reference
.extern Pico_mcd
.extern cdc_host_r
.extern Pico
.extern Read_CDC_Host
.extern m68k_reg_write8
.extern s68k_reg_read16
.extern s68k_reg_write8
.extern s68k_reg_write16
.extern s68k_poll_detect
.extern pcd_pcm_write
.extern pcd_pcm_read
.extern gfx_cd_read
.extern gfx_cd_write16
.extern PicoCpuCS68k
.extern PicoRead8_io
.extern PicoRead16_io
.extern PicoWrite8_io
.extern PicoWrite16_io
.extern m68k_comm_check
PIC_LDR_INIT()
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ -75,16 +71,16 @@
@ r0=addr[in,out], r1,r2=tmp
.macro cell_map
ands r1, r0, #0x01c000
PIC_XB(ne ,r1, lsr #12)
b 0f @ most common?
PIC_BT(0f)
PIC_BT(0f)
PIC_BT(0f)
PIC_BT(0f)
PIC_BT(1f)
PIC_BT(1f)
PIC_BT(2f)
PIC_BT(3f)
ldrne pc, [pc, r1, lsr #12]
beq 0f @ most common?
.long 0f
.long 0f
.long 0f
.long 0f
.long 1f
.long 1f
.long 2f
.long 3f
1: @ x16 cells
and r1, r0, #0x7e00 @ col
and r2, r0, #0x01fc @ row
@ -130,48 +126,44 @@ PicoReadM68k8_cell1: @ 0x220000 - 0x23ffff, cell arranged
mov r3, #0x0e0000
0:
cell_map
PIC_LDR(r1, r2, Pico_mcd)
ldr r1, =(Pico+0x22200)
add r0, r0, r3
ldr r1, [r1] @ Pico.mcd (used everywhere)
ldr r1, [r1]
eor r0, r0, #1
ldrb r0, [r1, r0]
bx lr
PicoRead8_mcd_io:
PicoReadM68k8_io:
and r1, r0, #0xff00
cmp r1, #0x2000 @ a120xx?
bne PicoRead8_io
PIC_LDR(r1, r2, Pico_mcd)
ldr r1, =(Pico+0x22200)
and r0, r0, #0x3f
ldr r1, [r1] @ Pico.mcd
ldr r1, [r1] @ Pico.mcd (used everywhere)
cmp r0, #0x0e
PIC_XB(lt ,r0, lsl #2)
ldrlt pc, [pc, r0, lsl #2]
b m_m68k_read8_hi
PIC_BT(m_m68k_read8_r00)
PIC_BT(m_m68k_read8_r01)
PIC_BT(m_m68k_read8_r02)
PIC_BT(m_m68k_read8_r03)
PIC_BT(m_m68k_read8_r04)
PIC_BT(m_read_null) @ unused bits
PIC_BT(m_m68k_read8_r06)
PIC_BT(m_m68k_read8_r07)
PIC_BT(m_m68k_read8_r08)
PIC_BT(m_m68k_read8_r09)
PIC_BT(m_read_null) @ reserved
PIC_BT(m_read_null)
PIC_BT(m_m68k_read8_r0c)
PIC_BT(m_m68k_read8_r0d)
.long m_m68k_read8_r00
.long m_m68k_read8_r01
.long m_m68k_read8_r02
.long m_m68k_read8_r03
.long m_m68k_read8_r04
.long m_read_null @ unused bits
.long m_m68k_read8_r06
.long m_m68k_read8_r07
.long m_m68k_read8_r08
.long m_m68k_read8_r09
.long m_read_null @ reserved
.long m_read_null
.long m_m68k_read8_r0c
.long m_m68k_read8_r0d
m_m68k_read8_r00:
add r1, r1, #0x110000
ldr r0, [r1, #0x30] @ Pico_mcd->s68k_regs
add r1, r1, #0x002200
ldr r1, [r1, #4] @ Pico_mcd->m.state_flags
ldr r0, [r1, #0x30]
and r0, r0, #0x04000000 @ we need irq2 mask state
mov r0, r0, lsr #19
and r1, r1, #0x00000100 @ irq2 pending
orr r0, r0, r1, lsr #8
bx lr
m_m68k_read8_r01:
add r1, r1, #0x110000
@ -182,15 +174,16 @@ m_m68k_read8_r02:
add r1, r1, #0x110000
ldrb r0, [r1, #2]
bx lr
m_m68k_read8_r03:
add r1, r1, #0x110000
stmfd sp!, {r1, lr}
bic r0, r0, #1
bl m68k_comm_check
ldmfd sp!, {r1, lr}
ldrb r0, [r1, #3]
and r0, r0, #0xc7
bx lr
m_m68k_read8_r03: @ FIXME: sync with C
add r2, r1, #0x110000
ldrb r1, [r2, #3]
add r2, r2, #0x002200
ldr r2, [r2, #4]
and r1, r1, #0xc7
tst r2, #2 @ DMNA pending?
bicne r1, r1, #1
orrne r1, r1, #2
b m68k_comm_check
m_m68k_read8_r04:
add r1, r1, #0x110000
ldrb r0, [r1, #4]
@ -199,38 +192,35 @@ m_m68k_read8_r06:
ldrb r0, [r1, #0x73] @ IRQ vector
bx lr
m_m68k_read8_r07:
PIC_LDR(r1, r2, Pico)
ldr r1, [r1, #OFS_Pico_rom]
ldrb r0, [r1, #0x72]
bx lr
m_m68k_read8_r08:
mov r0, #0
bl cdc_host_r
bl Read_CDC_Host @ TODO: make it local
mov r0, r0, lsr #8
bx lr
m_m68k_read8_r09:
mov r0, #0
b cdc_host_r
b Read_CDC_Host
m_m68k_read8_r0c:
mov r1, #0
bl pcd_stopwatch_read
mov r0, r0, lsr #8
add r1, r1, #0x110000
add r1, r1, #0x002200
ldr r0, [r1, #0x14] @ Pico_mcd->m.timer_stopwatch
mov r0, r0, lsr #24
bx lr
m_m68k_read8_r0d:
mov r1, #0
b pcd_stopwatch_read
add r1, r1, #0x110000
add r1, r1, #0x002200
ldr r0, [r1, #0x14]
mov r0, r0, lsr #16
bx lr
m_m68k_read8_hi:
cmp r0, #0x30
add r1, r1, #0x110000
movge r0, #0
bxge lr
add r1, r1, r0
stmfd sp!, {r1, lr}
bic r0, r0, #1
bl m68k_comm_check
ldmfd sp!, {r1, lr}
ldrb r0, [r1]
bx lr
bxeq lr
add r1, r1, #0x110000
ldrb r1, [r1, r0]
b m68k_comm_check
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ -244,85 +234,80 @@ PicoReadM68k16_cell1: @ 0x220000 - 0x23ffff, cell arranged
mov r3, #0x0e0000
0:
cell_map
PIC_LDR(r1, r2, Pico_mcd)
ldr r1, =(Pico+0x22200)
add r0, r0, r3
ldr r1, [r1] @ Pico.mcd
ldr r1, [r1]
bic r0, r0, #1
ldrh r0, [r1, r0]
bx lr
PicoRead16_mcd_io:
PicoReadM68k16_io:
and r1, r0, #0xff00
cmp r1, #0x2000 @ a120xx
bne PicoRead16_io
m_m68k_read16_m68k_regs:
PIC_LDR(r1, r2, Pico_mcd)
ldr r1, =(Pico+0x22200)
and r0, r0, #0x3e
ldr r1, [r1] @ Pico.mcd
ldr r1, [r1] @ Pico.mcd (used everywhere)
cmp r0, #0x0e
PIC_XB(lt ,r0, lsl #1)
ldrlt pc, [pc, r0, lsl #1]
b m_m68k_read16_hi
PIC_BT(m_m68k_read16_r00)
PIC_BT(m_m68k_read16_r02)
PIC_BT(m_m68k_read16_r04)
PIC_BT(m_m68k_read16_r06)
PIC_BT(m_m68k_read16_r08)
PIC_BT(m_read_null) @ reserved
PIC_BT(m_m68k_read16_r0c)
.long m_m68k_read16_r00
.long m_m68k_read16_r02
.long m_m68k_read16_r04
.long m_m68k_read16_r06
.long m_m68k_read16_r08
.long m_read_null @ reserved
.long m_m68k_read16_r0c
m_m68k_read16_r00:
add r1, r1, #0x110000
ldr r0, [r1, #0x30]
add r1, r1, #0x002200
ldrb r2, [r1, #2] @ Pico_mcd->m.busreq
ldr r1, [r1, #4]
ldrb r1, [r1, #2] @ Pico_mcd->m.busreq
and r0, r0, #0x04000000 @ we need irq2 mask state
orr r0, r2, r0, lsr #11
and r1, r1, #0x00000100 @ irq2 pending
orr r0, r1, r0
orr r0, r1, r0, lsr #11
bx lr
m_m68k_read16_r02:
add r1, r1, #0x110000
stmfd sp!, {r1, lr}
bl m68k_comm_check
ldmfd sp!, {r1, lr}
ldrb r2, [r1, #3]
ldrb r0, [r1, #2]
m_m68k_read16_r02: @ FIXME: out of sync from C
add r3, r1, #0x110000
ldrb r1, [r3, #2]
ldrb r2, [r3, #3]
add r3, r3, #0x002200
ldr r3, [r3, #4]
and r2, r2, #0xc7
orr r0, r2, r0, lsl #8
bx lr
orr r1, r2, r1, lsl #8
tst r3, #2 @ DMNA pending?
bicne r1, r1, #1
orrne r1, r1, #2
b m68k_comm_check
m_m68k_read16_r04:
add r1, r1, #0x110000
ldrb r0, [r1, #4]
mov r0, r0, lsl #8
bx lr
m_m68k_read16_r06:
PIC_LDR(r1, r2, Pico)
ldr r1, [r1, #OFS_Pico_rom]
ldrh r0, [r1, #0x72] @ IRQ vector
bx lr
m_m68k_read16_r08:
mov r0, #0
b cdc_host_r
b Read_CDC_Host
m_m68k_read16_r0c:
mov r1, #0
b pcd_stopwatch_read
add r1, r1, #0x110000
add r1, r1, #0x002200
ldr r0, [r1, #0x14]
mov r0, r0, lsr #16
bx lr
m_m68k_read16_hi:
cmp r0, #0x30
add r1, r1, #0x110000
addlt r1, r1, #0x110000
ldrlth r1, [r1, r0]
movge r0, #0
bxge lr
add r1, r0, r1
stmfd sp!, {r1, lr}
bl m68k_comm_check
ldmfd sp!, {r0, lr}
ldrh r0, [r0]
mov r1, r0, lsr #8
and r0, r0, #0xff
orr r0, r1, r0, lsl #8
bx lr
mov r2, r1, lsr #8
and r1, r1, #0xff
orr r1, r2, r1, lsl #8
b m68k_comm_check
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ -337,16 +322,15 @@ PicoWriteM68k8_cell1: @ 0x220000 - 0x23ffff, cell arranged
0:
mov r3, r1
cell_map
PIC_LDR(r2, r1, Pico_mcd)
ldr r2, =(Pico+0x22200)
add r0, r0, r12
ldr r2, [r2] @ Pico.mcd
ldr r2, [r2]
eor r0, r0, #1
strb r3, [r2, r0]
bx lr
PicoWrite8_mcd_io:
PicoWriteM68k8_io:
and r2, r0, #0xff00
cmp r2, #0x2000 @ a120xx?
beq m68k_reg_write8
@ -365,15 +349,15 @@ PicoWriteM68k16_cell1: @ 0x220000 - 0x23ffff, cell arranged
0:
mov r3, r1
cell_map
PIC_LDR(r1, r2, Pico_mcd)
ldr r1, =(Pico+0x22200)
add r0, r0, r12
ldr r1, [r1] @ Pico.mcd
ldr r1, [r1]
bic r0, r0, #1
strh r3, [r1, r0]
bx lr
PicoWrite16_mcd_io:
PicoWriteM68k16_io:
and r2, r0, #0xff00
cmp r2, #0x2000 @ a120xx?
bne PicoWrite16_io
@ -384,10 +368,10 @@ m_m68k_write16_regs:
beq m_m68k_write16_regs_spec
and r3, r1, #0xff
add r2, r0, #1
stmfd sp!,{r2,r3,r12,lr}
stmfd sp!,{r2,r3,lr}
mov r1, r1, lsr #8
bl m68k_reg_write8
ldmfd sp!,{r0,r1,r12,lr}
ldmfd sp!,{r0,r1,lr}
b m68k_reg_write8
m_m68k_write16_regs_spec: @ special case
@ -407,9 +391,9 @@ PicoReadS68k8_dec0: @ 0x080000 - 0x0bffff
PicoReadS68k8_dec1:
mov r3, #0x0a0000 @ + ^ / 2
0:
PIC_LDR(r2, r1, Pico_mcd)
ldr r2, =(Pico+0x22200)
eor r0, r0, #2
ldr r2, [r2] @ Pico.mcd
ldr r2, [r2]
movs r0, r0, lsr #1 @ +4-6 <<16
add r2, r2, r3 @ map to our address
ldrb r0, [r2, r0]
@ -429,9 +413,14 @@ m_s68k_read8_regs:
sub r2, r0, #0x0e
cmp r2, #(0x30-0x0e)
blo m_s68k_read8_comm
sub r2, r0, #0x58
cmp r2, #0x10
ldrlo r2, =gfx_cd_read
ldrhs r2, =s68k_reg_read16
stmfd sp!,{r0,lr}
bic r0, r0, #1
bl s68k_reg_read16
mov lr, pc
bx r2
ldmfd sp!,{r1,lr}
tst r1, #1
moveq r0, r0, lsr #8
@ -439,11 +428,10 @@ m_s68k_read8_regs:
bx lr
m_s68k_read8_comm:
PIC_LDR(r1, r2, Pico_mcd)
ldr r1, [r1] @ Pico.mcd
ldr r1, =(Pico+0x22200)
ldr r1, [r1]
add r1, r1, #0x110000
ldrb r1, [r1, r0]
bic r0, r0, #1
b s68k_poll_detect
@ -452,17 +440,25 @@ m_s68k_read8_pcm:
bne m_read_null
@ must not trash r3 and r12
PIC_LDR(r1, r2, Pico_mcd)
ldr r1, =(Pico+0x22200)
bic r0, r0, #0xff0000
ldr r1, [r1] @ Pico.mcd
@ bic r0, r0, #0x008000
ldr r1, [r1]
mov r2, #0x110000
orr r2, r2, #0x002200
cmp r0, #0x2000
bge m_s68k_read8_pcm_ram
cmp r0, #0x20
movge r0, r0, lsr #1
bge pcd_pcm_read
mov r0, #0
movlt r0, #0
bxlt lr
orr r2, r2, #(0x48+8) @ pcm.ch + addr_offset
add r1, r1, r2
and r2, r0, #0x1c
ldr r1, [r1, r2, lsl #2]
tst r0, #2
moveq r0, r1, lsr #PCM_STEP_SHIFT
movne r0, r1, lsr #(PCM_STEP_SHIFT+8)
and r0, r0, #0xff
bx lr
m_s68k_read8_pcm_ram:
@ -487,9 +483,9 @@ PicoReadS68k16_dec0: @ 0x080000 - 0x0bffff
PicoReadS68k16_dec1:
mov r3, #0x0a0000 @ + ^ / 2
0:
PIC_LDR(r2, r1, Pico_mcd)
ldr r2, =(Pico+0x22200)
eor r0, r0, #2
ldr r2, [r2] @ Pico.mcd
ldr r2, [r2]
mov r0, r0, lsr #1 @ +4-6 <<16
add r2, r2, r3 @ map to our address
ldrb r0, [r2, r0]
@ -508,18 +504,22 @@ m_s68k_read16_regs:
bic r0, r0, #0xff0000
bic r0, r0, #0x008000
bic r0, r0, #0x000001
sub r2, r0, #0x58
cmp r2, #0x10
blo gfx_cd_read
cmp r0, #8
bne s68k_reg_read16
mov r0, #1
b cdc_host_r
b Read_CDC_Host
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.macro m_s68k_write8_2M_decode
PIC_LDR(r2, ip, Pico_mcd)
ldr r2, =(Pico+0x22200)
eor r0, r0, #2
ldr r2, [r2] @ Pico.mcd
ldr r2, [r2] @ Pico.rom
movs r0, r0, lsr #1 @ +4-6 <<16
add r2, r2, r3 @ map to our address
.endm
@ -581,12 +581,12 @@ m_s68k_write8_regs:
tst r0, #0x7e00
movne r0, #0
bxne lr
sub r2, r0, #0x59
cmp r2, #0x0f
sub r2, r0, #0x58
cmp r2, #0x10
bhs s68k_reg_write8
bic r0, r0, #1
orr r1, r1, r1, lsl #8
b s68k_reg_write16
b gfx_cd_write16
m_s68k_write8_pcm:
@ -595,15 +595,15 @@ m_s68k_write8_pcm:
bic r0, r0, #0xff0000
cmp r0, #0x12
movlt r0, r0, lsr #1
blt pcd_pcm_write
blt pcm_write
cmp r0, #0x2000
bxlt lr
m_s68k_write8_pcm_ram:
PIC_LDR(r3, r2, Pico_mcd)
ldr r3, =(Pico+0x22200)
bic r0, r0, #0x00e000
ldr r3, [r3] @ Pico.mcd
ldr r3, [r3]
mov r0, r0, lsr #1
add r2, r3, #0x110000
add r2, r2, #0x002200
@ -615,13 +615,14 @@ m_s68k_write8_pcm_ram:
strb r1, [r3, r0]
bx lr
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.macro m_s68k_write16_2M_decode
PIC_LDR(r2, ip, Pico_mcd)
ldr r2, =(Pico+0x22200)
eor r0, r0, #2
ldr r2, [r2] @ Pico.mcd
ldr r2, [r2]
mov r0, r0, lsr #1 @ +4-6 <<16
add r2, r2, r3 @ map to our address
.endm
@ -697,113 +698,26 @@ m_s68k_write16_regs:
movne r0, #0
bxne lr
cmp r0, #0x0e
bne s68k_reg_write16
beq m_s68k_write16_regs_spec
sub r2, r0, #0x58
cmp r2, #0x10
blo gfx_cd_write16
and r3, r1, #0xff
add r2, r0, #1
stmfd sp!,{r2,r3,lr}
mov r1, r1, lsr #8
bl s68k_reg_write8
ldmfd sp!,{r0,r1,lr}
b s68k_reg_write8
m_s68k_write16_regs_spec: @ special case
PIC_LDR(r2, r0, Pico_mcd)
ldr r2, =(Pico+0x22200)
mov r0, #0x110000
ldr r2, [r2] @ Pico.mcd
ldr r2, [r2]
add r0, r0, #0x00000f
strb r1, [r2, r0] @ if (a == 0xe) s68k_regs[0xf] = d;
bx lr
.global s68k_read8
.global s68k_read16
.global s68k_read32
.global s68k_write8
.global s68k_write16
.global s68k_write32
s68k_read8:
PIC_LDR(r3, r2, s68k_read8_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
eor r2, r0, #1
movs r3, r3, lsl #1
ldrccb r0, [r3, r2]
bxcc lr
bx r3
s68k_read16:
PIC_LDR(r3, r2, s68k_read16_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
bic r0, r0, #1
movs r3, r3, lsl #1
ldrcch r0, [r3, r0]
bxcc lr
bx r3
s68k_read32:
PIC_LDR(r3, r2, s68k_read16_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
bic r0, r0, #1
movs r3, r3, lsl #1
ldrcch r1, [r3, r0]!
ldrcch r0, [r3, #2]
orrcc r0, r0, r1, lsl #16
bxcc lr
stmfd sp!, {r0, r3, r4, lr}
mov lr, pc
bx r3
ldmfd sp!, {r1, r3}
str r0, [sp]
add r0, r1, #2
mov lr, pc
bx r3
ldmfd sp!, {r1, lr}
mov r0, r0, lsl #16
mov r1, r1, lsl #16
orr r0, r1, r0, lsr #16
bx lr
s68k_write8:
PIC_LDR(r3, r2, s68k_write8_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
eor r2, r0, #1
movs r3, r3, lsl #1
strccb r1, [r3, r2]
bxcc lr
bx r3
s68k_write16:
PIC_LDR(r3, r2, s68k_write16_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
bic r0, r0, #1
movs r3, r3, lsl #1
strcch r1, [r3, r0]
bxcc lr
bx r3
s68k_write32:
PIC_LDR(r3, r2, s68k_write16_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
bic r0, r0, #1
movs r3, r3, lsl #1
movcc r2, r1, lsr #16
strcch r2, [r3, r0]!
strcch r1, [r3, #2]
bxcc lr
stmfd sp!, {r0, r1, r3, lr}
mov r1, r1, lsr #16
mov lr, pc
bx r3
ldmfd sp!, {r0, r1, r3, lr}
add r0, r0, #2
bx r3
.pool
@ vim:filetype=armasm

View file

@ -1,166 +1,137 @@
/*
* Emulation routines for the RF5C164 PCM chip
* (C) notaz, 2007, 2013
* (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 "pcm.h"
#define PCM_STEP_SHIFT 11
static unsigned int g_rate = 0; // 18.14 fixed point
void pcd_pcm_write(unsigned int a, unsigned int d)
PICO_INTERNAL_ASM void 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);
//printf("pcm_write(%i, %02x)\n", a, d);
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;
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;
// dprintf("pcm control=%02x", Pico_mcd->pcm.control);
}
else if (a == 8) // sound on/off
{
if (!(Pico_mcd->pcm.enabled & 0x01)) Pico_mcd->pcm.ch[0].addr =
Pico_mcd->pcm.ch[0].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x02)) Pico_mcd->pcm.ch[1].addr =
Pico_mcd->pcm.ch[1].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x04)) Pico_mcd->pcm.ch[2].addr =
Pico_mcd->pcm.ch[2].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x08)) Pico_mcd->pcm.ch[3].addr =
Pico_mcd->pcm.ch[3].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x10)) Pico_mcd->pcm.ch[4].addr =
Pico_mcd->pcm.ch[4].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x20)) Pico_mcd->pcm.ch[5].addr =
Pico_mcd->pcm.ch[5].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x40)) Pico_mcd->pcm.ch[6].addr =
Pico_mcd->pcm.ch[6].regs[6] << (PCM_STEP_SHIFT + 8);
if (!(Pico_mcd->pcm.enabled & 0x80)) Pico_mcd->pcm.ch[7].addr =
Pico_mcd->pcm.ch[7].regs[6] << (PCM_STEP_SHIFT + 8);
// printf("addr %x %x %x %x %x %x %x %x\n", Pico_mcd->pcm.ch[0].addr, Pico_mcd->pcm.ch[1].addr
// , Pico_mcd->pcm.ch[2].addr, Pico_mcd->pcm.ch[3].addr, Pico_mcd->pcm.ch[4].addr, Pico_mcd->pcm.ch[5].addr
// , Pico_mcd->pcm.ch[6].addr, Pico_mcd->pcm.ch[7].addr);
Pico_mcd->pcm.enabled = ~d;
//printf("enabled=%02x\n", Pico_mcd->pcm.enabled);
}
}
unsigned int pcd_pcm_read(unsigned int a)
PICO_INTERNAL void pcm_set_rate(int rate)
{
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;
float step = 31.8 * 1024.0 / (float) rate; // max <4 @ 8000Hz
step *= 256*256/4;
g_rate = (unsigned int) step;
if (step - (float) g_rate >= 0.5) g_rate++;
elprintf(EL_STATUS, "g_rate: %f %08x\n", (double)step, g_rate);
}
void pcd_pcm_sync(unsigned int to)
PICO_INTERNAL void pcm_update(int *buffer, int length, int stereo)
{
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;
struct pcm_chan *ch;
unsigned int step, addr;
int mul_l, mul_r, smp;
int i, j, k;
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 (to be checked by caller)
//if (!(Pico_mcd->pcm.control & 0x80) || !Pico_mcd->pcm.enabled) return;
// 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;
//printf("-- upd %i\n", length);
out = Pico_mcd->pcm_mixbuf + Pico_mcd->pcm_mixpos * 2;
Pico_mcd->pcm_mixbuf_dirty = 1;
Pico_mcd->pcm_regs_dirty = 0;
for (i = 0; i < 8; i++)
{
if (!(Pico_mcd->pcm.enabled & (1 << i))) continue; // channel disabled
for (c = 0; c < 8; c++)
{
ch = &Pico_mcd->pcm.ch[c];
out = buffer;
ch = &Pico_mcd->pcm.ch[i];
if (!(enabled & (1 << c))) {
ch->addr = ch->regs[6] << (PCM_STEP_SHIFT + 8);
continue; // channel disabled
}
addr = ch->addr; // >> PCM_STEP_SHIFT;
mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1); // (env * pan) >> 5
mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1);
step = ((unsigned int)(*(unsigned short *)&ch->regs[2]) * g_rate) >> 14; // freq step
// fprintf(stderr, "step=%i, cstep=%i, mul_l=%i, mul_r=%i, ch=%i, addr=%x, en=%02x\n",
// *(unsigned short *)&ch->regs[2], step, mul_l, mul_r, i, addr, Pico_mcd->pcm.enabled);
addr = ch->addr;
inc = ch->regs[2] + (ch->regs[3]<<8);
mul_l = (int)ch->regs[0] * (ch->regs[1] & 0xf);
mul_r = (int)ch->regs[0] * (ch->regs[1] >> 4);
if (!stereo && mul_l < mul_r) mul_l = mul_r;
for (s = 0; s < steps; s++)
{
smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
for (j = 0; j < length; j++)
{
// printf("addr=%08x\n", addr);
smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
// test for loop signal
if (smp == 0xff)
{
addr = ch->regs[4] + (ch->regs[5]<<8); // loop_addr
smp = Pico_mcd->pcm_ram[addr];
addr <<= PCM_STEP_SHIFT;
if (smp == 0xff)
break;
} else
addr = (addr + inc) & 0x07FFFFFF;
// 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);
if (smp & 0x80) smp = -(smp & 0x7f);
out[s*2 ] += (smp * mul_l) >> 5; // max 127 * 255 * 15 / 32 = 15180
out[s*2+1] += (smp * mul_r) >> 5;
}
ch->addr = addr;
}
*out++ += smp * mul_l; // max 128 * 119 = 15232
if(stereo)
*out++ += smp * mul_r;
end:
Pico_mcd->pcm.update_cycles = cycles + steps * 384;
Pico_mcd->pcm_mixpos += steps;
// update address register
k = (addr >> PCM_STEP_SHIFT) + 1;
addr = (addr + step) & 0x7FFFFFF;
for(; k < (addr >> PCM_STEP_SHIFT); k++)
{
if (Pico_mcd->pcm_ram[k] == 0xff)
{
addr = (unsigned int)(*(unsigned short *)&ch->regs[4]) << PCM_STEP_SHIFT; // loop_addr
break;
}
}
}
if (Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT] == 0xff)
addr = (unsigned int)(*(unsigned short *)&ch->regs[4]) << PCM_STEP_SHIFT; // loop_addr
ch->addr = addr;
}
}
void pcd_pcm_update(s32 *buf32, int length, int stereo)
{
int step, *pcm;
int p = 0;
pcd_pcm_sync(SekCyclesDoneS68k());
if (!Pico_mcd->pcm_mixbuf_dirty || !(PicoIn.opt & POPT_EN_MCD_PCM) || !buf32)
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

7
pico/cd/pcm.h Normal file
View file

@ -0,0 +1,7 @@
#define PCM_STEP_SHIFT 11
PICO_INTERNAL_ASM void pcm_write(unsigned int a, unsigned int d);
PICO_INTERNAL void pcm_set_rate(int rate);
PICO_INTERNAL void pcm_update(int *buffer, int length, int stereo);

View file

@ -32,8 +32,6 @@ static int new_irq_level(int level)
{
int level_new = 0, irqs;
Pico_mcd->m.s68k_pend_ints &= ~(1 << level);
if (level == 2) // clear pending bit
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_IFL2;
irqs = Pico_mcd->m.s68k_pend_ints;
irqs &= Pico_mcd->s68k_regs[0x33];
while ((irqs >>= 1)) level_new++;
@ -119,10 +117,15 @@ PICO_INTERNAL void SekInitS68k(void)
}
#endif
#ifdef EMU_F68K
memset(&PicoCpuFS68k, 0, sizeof(PicoCpuFS68k));
fm68k_init();
PicoCpuFS68k.iack_handler = SekIntAckFS68k;
PicoCpuFS68k.sr = 0x2704; // Z flag
{
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
}
@ -146,7 +149,12 @@ PICO_INTERNAL int SekResetS68k(void)
}
#endif
#ifdef EMU_F68K
fm68k_reset(&PicoCpuFS68k);
{
void *oldcontext = g_m68kcontext;
g_m68kcontext = &PicoCpuFS68k;
fm68k_reset();
g_m68kcontext = oldcontext;
}
#endif
return 0;
@ -170,8 +178,10 @@ PICO_INTERNAL int SekInterruptS68k(int irq)
PicoCpuCS68k.irq=real_irq;
#endif
#ifdef EMU_M68K
// avoid m68k_set_irq() for delaying to work
PicoCpuMS68k.int_level = real_irq << 8;
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;
@ -179,17 +189,3 @@ PICO_INTERNAL int SekInterruptS68k(int irq)
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
}

View file

@ -8,7 +8,6 @@
#include "pico_int.h"
#include "sound/ym2612.h"
#include "memory.h"
#include "debug.h"
#define bit(r, x) ((r>>x)&1)
@ -21,12 +20,13 @@ char *PDebugMain(void)
{
struct PicoVideo *pv=&Pico.video;
unsigned char *reg=pv->reg, r;
extern int HighPreSpr[];
int i, sprites_lo, sprites_hi;
char *dstrp;
sprites_lo = sprites_hi = 0;
for (i = 0; Pico.est.HighPreSpr[i] != 0; i+=2)
if (Pico.est.HighPreSpr[i+1] & 0x8000)
for (i = 0; HighPreSpr[i] != 0; i+=2)
if (HighPreSpr[i+1] & 0x8000)
sprites_hi++;
else sprites_lo++;
@ -40,19 +40,13 @@ char *PDebugMain(void)
sprintf(dstrp, "mode set 4: %02x\n", (r=reg[0xC])); MVP;
sprintf(dstrp, "interlace: %i%i, cells: %i, shadow: %i\n", bit(r,2), bit(r,1), (r&0x80) ? 40 : 32, bit(r,3)); MVP;
sprintf(dstrp, "scroll size: w: %i, h: %i SRAM: %i; eeprom: %i (%i)\n", reg[0x10]&3, (reg[0x10]&0x30)>>4,
!!(Pico.sv.flags & SRF_ENABLED), !!(Pico.sv.flags & SRF_EEPROM), Pico.sv.eeprom_type); MVP;
sprintf(dstrp, "sram range: %06x-%06x, reg: %02x\n", Pico.sv.start, Pico.sv.end, Pico.m.sram_reg); MVP;
!!(SRam.flags & SRF_ENABLED), !!(SRam.flags & SRF_EEPROM), SRam.eeprom_type); MVP;
sprintf(dstrp, "sram range: %06x-%06x, reg: %02x\n", SRam.start, SRam.end, Pico.m.sram_reg); MVP;
sprintf(dstrp, "pend int: v:%i, h:%i, vdp status: %04x\n", bit(pv->pending_ints,5), bit(pv->pending_ints,4), pv->status); MVP;
sprintf(dstrp, "VDP regs 00-07: %02x %02x %02x %02x %02x %02x %02x %02x\n",reg[0],reg[1],reg[2],reg[3],reg[4],reg[5],reg[6],reg[7]); MVP;
sprintf(dstrp, "VDP regs 08-0f: %02x %02x %02x %02x %02x %02x %02x %02x\n",reg[8],reg[9],reg[10],reg[11],reg[12],reg[13],reg[14],reg[15]); MVP;
sprintf(dstrp, "VDP regs 10-17: %02x %02x %02x %02x %02x %02x %02x %02x\n",reg[16],reg[17],reg[18],reg[19],reg[20],reg[21],reg[22],reg[23]); MVP;
sprintf(dstrp, "VDP regs 18-1f: %02x %02x %02x %02x %02x %02x %02x %02x\n",reg[24],reg[25],reg[26],reg[27],reg[28],reg[29],reg[30],reg[31]); MVP;
r = (reg[5]<<9)+(reg[6]<<11);
sprintf(dstrp, "sprite #0: %04x %04x %04x %04x\n",PicoMem.vram[r/2],PicoMem.vram[r/2+1],PicoMem.vram[r/2+2],PicoMem.vram[r/2+3]); MVP;
sprintf(dstrp, "pal: %i, hw: %02x, frame#: %i, cycles: %u\n", Pico.m.pal, Pico.m.hardware, Pico.m.frame_count, SekCyclesDone()); MVP;
sprintf(dstrp, "M68k: PC: %06lx, SR: %04x, irql: %i\n", (ulong)SekPc, SekSr, SekIrqLevel); MVP;
sprintf(dstrp, "pal: %i, hw: %02x, frame#: %i, cycles: %i\n", Pico.m.pal, Pico.m.hardware, Pico.m.frame_count, SekCyclesDone()); MVP;
sprintf(dstrp, "M68k: PC: %06x, SR: %04x, irql: %i\n", SekPc, SekSr, SekIrqLevel); MVP;
for (r = 0; r < 8; r++) {
sprintf(dstrp, "d%i=%08lx, a%i=%08lx\n", r, (ulong)SekDar(r), r, (ulong)SekDar(r+8)); MVP;
sprintf(dstrp, "d%i=%08x, a%i=%08x\n", r, SekDar(r), r, SekDar(r+8)); MVP;
}
sprintf(dstrp, "z80Run: %i, z80_reset: %i, z80_bnk: %06x\n", Pico.m.z80Run, Pico.m.z80_reset, Pico.m.z80_bank68k<<15); MVP;
z80_debug(dstrp); MVP;
@ -77,7 +71,7 @@ char *PDebug32x(void)
}
r = Pico32x.sh2_regs;
sprintf(dstrp, "SH: %04x %04x %04x IRQs: %02x eflags: %02x\n",
r[0], r[1], r[2], Pico32x.sh2irqi[0]|Pico32x.sh2irqi[1], Pico32x.emu_flags); MVP;
r[0], r[1], r[2], Pico32x.sh2irqs, Pico32x.emu_flags); MVP;
i = 0;
r = Pico32x.vdp_regs;
@ -86,12 +80,12 @@ char *PDebug32x(void)
i*2, r[i+0], r[i+1], r[i+2], r[i+3], r[i+4], r[i+5], r[i+6], r[i+7]); MVP;
sprintf(dstrp, " mSH2 sSH2\n"); MVP;
sprintf(dstrp, "PC,SR %08lx, %03x %08lx, %03x\n", (ulong)sh2_pc(&msh2), (uint)sh2_sr(0), (ulong)sh2_pc(&ssh2), (uint)sh2_sr(1)); MVP;
sprintf(dstrp, "PC,SR %08x, %03x %08x, %03x\n", sh2_pc(&msh2), sh2_sr(0), sh2_pc(&ssh2), sh2_sr(1)); MVP;
for (i = 0; i < 16/2; i++) {
sprintf(dstrp, "R%d,%2d %08lx,%08lx %08lx,%08lx\n", i, i + 8,
(ulong)sh2_reg(0,i), (ulong)sh2_reg(0,i+8), (ulong)sh2_reg(1,i), (ulong)sh2_reg(1,i+8)); MVP;
sprintf(dstrp, "R%d,%2d %08x,%08x %08x,%08x\n", i, i + 8,
sh2_reg(0,i), sh2_reg(0,i+8), sh2_reg(1,i), sh2_reg(1,i+8)); MVP;
}
sprintf(dstrp, "gb,vb %08lx,%08lx %08lx,%08lx\n", (ulong)sh2_gbr(0), (ulong)sh2_vbr(0), (ulong)sh2_gbr(1), (ulong)sh2_vbr(1)); MVP;
sprintf(dstrp, "gb,vb %08x,%08x %08x,%08x\n", sh2_gbr(0), sh2_vbr(0), sh2_gbr(1), sh2_vbr(1)); MVP;
sprintf(dstrp, "IRQs/mask: %02x/%02x %02x/%02x\n",
Pico32x.sh2irqi[0], Pico32x.sh2irq_mask[0], Pico32x.sh2irqi[1], Pico32x.sh2irq_mask[1]); MVP;
#else
@ -123,7 +117,7 @@ char *PDebugSpriteList(void)
unsigned int *sprite;
int code, code2, sx, sy, height;
sprite=(unsigned int *)(PicoMem.vram+((table+(link<<2))&0x7ffc)); // Find sprite
sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
// get sprite info
code = sprite[0];
@ -148,11 +142,7 @@ char *PDebugSpriteList(void)
}
#define GREEN1 0x0700
#if defined(USE_BGR555)
#define YELLOW1 0x039c
#define BLUE1 0x7800
#define RED1 0x001e
#elif defined(USE_BGR565)
#ifdef USE_BGR555
#define YELLOW1 0x071c
#define BLUE1 0xf000
#define RED1 0x001e
@ -207,30 +197,29 @@ void PDebugShowSpriteStats(unsigned short *screen, int stride)
void PDebugShowPalette(unsigned short *screen, int stride)
{
struct PicoEState *est = &Pico.est;
int x, y;
Pico.m.dirtyPal = 1;
if (PicoIn.AHW & PAHW_SMS)
PicoDoHighPal555SMS();
if (PicoAHW & PAHW_SMS)
PicoDoHighPal555M4();
else
PicoDoHighPal555(1, 0, est);
PicoDoHighPal555(1);
Pico.m.dirtyPal = 1;
screen += 16*stride+8;
for (y = 0; y < 8*4; y++)
for (x = 0; x < 8*16; x++)
screen[x + y*stride] = est->HighPal[x/8 + (y/8)*16];
screen[x + y*stride] = HighPal[x/8 + (y/8)*16];
screen += 160;
for (y = 0; y < 8*4; y++)
for (x = 0; x < 8*16; x++)
screen[x + y*stride] = est->HighPal[(x/8 + (y/8)*16) | 0x40];
screen[x + y*stride] = HighPal[(x/8 + (y/8)*16) | 0x40];
screen += stride*48;
for (y = 0; y < 8*4; y++)
for (x = 0; x < 8*16; x++)
screen[x + y*stride] = est->HighPal[(x/8 + (y/8)*16) | 0x80];
screen[x + y*stride] = HighPal[(x/8 + (y/8)*16) | 0x80];
}
#if defined(DRAW2_OVERRIDE_LINE_WIDTH)
@ -244,7 +233,6 @@ void PDebugShowSprite(unsigned short *screen, int stride, int which)
struct PicoVideo *pvid=&Pico.video;
int table=0,u,link=0,*sprite=0,*fsprite,oldsprite[2];
int x,y,max_sprites = 80, oldcol, oldreg;
unsigned char olddbg;
if (!(pvid->reg[12]&1))
max_sprites = 64;
@ -255,42 +243,41 @@ void PDebugShowSprite(unsigned short *screen, int stride, int which)
for (u=0; u < max_sprites && u <= which; u++)
{
sprite=(int *)(PicoMem.vram+((table+(link<<2))&0x7ffc)); // Find sprite
sprite=(int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
link=(sprite[0]>>16)&0x7f;
if (!link) break; // End of sprites
}
if (u >= max_sprites) return;
fsprite = (int *)(PicoMem.vram+(table&0x7ffc));
fsprite = (int *)(Pico.vram+(table&0x7ffc));
oldsprite[0] = fsprite[0];
oldsprite[1] = fsprite[1];
fsprite[0] = (sprite[0] & ~0x007f01ff) | 0x000080;
fsprite[1] = (sprite[1] & ~0x01ff8000) | 0x800000;
oldreg = pvid->reg[7];
oldcol = PicoMem.cram[0];
olddbg = pvid->debug_p;
oldcol = Pico.cram[0];
pvid->reg[7] = 0;
PicoMem.cram[0] = 0;
pvid->debug_p = PVD_KILL_A | PVD_KILL_B;
Pico.cram[0] = 0;
PicoDrawMask = PDRAW_SPRITES_LOW_ON;
PicoFrameFull();
for (y = 0; y < 8*4; y++)
{
unsigned char *ps = Pico.est.Draw2FB + DRAW2_LINE_WIDTH*y + 8;
unsigned char *ps = PicoDraw2FB + DRAW2_LINE_WIDTH*y + 8;
for (x = 0; x < 8*4; x++)
if (ps[x]) screen[x] = Pico.est.HighPal[ps[x]], ps[x] = 0;
if (ps[x]) screen[x] = HighPal[ps[x]], ps[x] = 0;
screen += stride;
}
fsprite[0] = oldsprite[0];
fsprite[1] = oldsprite[1];
pvid->reg[7] = oldreg;
PicoMem.cram[0] = oldcol;
pvid->debug_p = olddbg;
Pico.cram[0] = oldcol;
PicoDrawMask = -1;
}
#define dump_ram_m(ram,fname,mode) \
#define dump_ram(ram,fname) \
{ \
unsigned short *sram = (unsigned short *) ram; \
FILE *f; \
@ -298,7 +285,7 @@ void PDebugShowSprite(unsigned short *screen, int stride, int which)
\
for (i = 0; i < sizeof(ram)/2; i++) \
sram[i] = (sram[i]<<8) | (sram[i]>>8); \
f = fopen(fname, mode); \
f = fopen(fname, "wb"); \
if (f) { \
fwrite(ram, 1, sizeof(ram), f); \
fclose(f); \
@ -307,9 +294,6 @@ void PDebugShowSprite(unsigned short *screen, int stride, int which)
sram[i] = (sram[i]<<8) | (sram[i]>>8); \
}
#define dump_ram(ram,fname) \
dump_ram_m(ram,fname,"wb")
#define dump_ram_noswab(ram,fname) \
{ \
FILE *f; \
@ -322,34 +306,21 @@ void PDebugShowSprite(unsigned short *screen, int stride, int which)
void PDebugDumpMem(void)
{
#if 0
char buf[1 << M68K_MEM_SHIFT];
unsigned int a;
for (a = 0; ; a++) {
uptr v = m68k_read16_map[a];
if (map_flag_set(v))
break;
v <<= 1;
v += a << M68K_MEM_SHIFT;
memcpy(buf, (void *)v, sizeof(buf));
dump_ram_m(buf, "dumps/cart.bin", a ? "ab" : "wb");
}
#endif
dump_ram_noswab(PicoMem.zram, "dumps/zram.bin");
dump_ram(PicoMem.cram, "dumps/cram.bin");
dump_ram_noswab(Pico.zram, "dumps/zram.bin");
dump_ram(Pico.cram, "dumps/cram.bin");
if (PicoIn.AHW & PAHW_SMS)
if (PicoAHW & PAHW_SMS)
{
dump_ram_noswab(PicoMem.vramb, "dumps/vram.bin");
dump_ram_noswab(Pico.vramb, "dumps/vram.bin");
}
else
{
dump_ram(PicoMem.ram, "dumps/ram.bin");
dump_ram(PicoMem.vram, "dumps/vram.bin");
dump_ram(PicoMem.vsram,"dumps/vsram.bin");
dump_ram(Pico.ram, "dumps/ram.bin");
dump_ram(Pico.vram, "dumps/vram.bin");
dump_ram(Pico.vsram,"dumps/vsram.bin");
}
if (PicoIn.AHW & PAHW_MCD)
if (PicoAHW & PAHW_MCD)
{
dump_ram(Pico_mcd->prg_ram, "dumps/prg_ram.bin");
if (Pico_mcd->s68k_regs[3]&4) // 1M mode?
@ -365,7 +336,7 @@ void PDebugDumpMem(void)
}
#ifndef NO_32X
if (PicoIn.AHW & PAHW_32X)
if (PicoAHW & PAHW_32X)
{
dump_ram(Pico32xMem->sdram, "dumps/sdram.bin");
dump_ram(Pico32xMem->dram[0], "dumps/dram0.bin");
@ -379,40 +350,50 @@ void PDebugDumpMem(void)
void PDebugZ80Frame(void)
{
int lines;
int lines, line_sample;
if (PicoIn.AHW & PAHW_SMS)
if (PicoAHW & PAHW_SMS)
return;
if (Pico.m.pal)
lines = 313;
else
if (Pico.m.pal) {
lines = 312;
line_sample = 68;
} else {
lines = 262;
line_sample = 93;
}
PsndStartFrame();
z80_resetCycles();
emustatus &= ~1;
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
PicoSyncZ80(Pico.t.m68c_cnt + 224 * 488);
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80))
PicoSyncZ80(line_sample*488);
if (ym2612.dacen && PsndDacLine <= line_sample)
PsndDoDAC(line_sample);
if (PsndOut)
PsndGetSamples(line_sample);
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80)) {
PicoSyncZ80(224*488);
z80_int();
}
if (ym2612.dacen && PsndDacLine <= 224)
PsndDoDAC(224);
if (PsndOut)
PsndGetSamples(224);
// sync z80
if (/*Pico.m.z80Run &&*/ !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
Pico.t.m68c_cnt += Pico.m.pal ? 151809 : 127671; // cycles adjusted for converter
PicoSyncZ80(Pico.t.m68c_cnt);
}
if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80))
PicoSyncZ80(Pico.m.pal ? 151809 : 127671); // cycles adjusted for converter
if (PsndOut && ym2612.dacen && PsndDacLine <= lines-1)
PsndDoDAC(lines-1);
if (PicoIn.sndOut)
PsndGetSamples(lines);
timers_cycle(Pico.t.z80c_aim);
z80_resetCycles();
Pico.t.m68c_aim = Pico.t.m68c_cnt;
timers_cycle();
}
void PDebugCPUStep(void)
{
if (PicoIn.AHW & PAHW_SMS)
if (PicoAHW & PAHW_SMS)
z80_run_nr(1);
else
SekStepM68k();

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