179 Commits
Author SHA1 Message Date
Flyinghead aa97a6d64f pvr: last naomi2 poly was ignored in some cases
Fix the disappearing moustache in wild riders
Fix other potential edge cases in pvr parsing
2022-08-25 19:34:23 +02:00
scribam 72136c2bfc deps: update sdl to version 2.24.0 2022-08-22 12:29:34 +02:00
scribam 7457db8bba android: update android gradle plugin to version 7.2.2 2022-08-06 17:30:10 +02:00
GABO1423 69125b490e (UWP) Build Tweaks (#709)
* (UWP) Disable Vulkan Build Flag

* (CI) Remove UWP Build Flag
2022-08-04 17:37:06 +02:00
vkedwardli 3c94cd3194 Fix macOS accent menu (#708)
* `SDL_StartTextInput` only when textfield is focused

* [macOS] "Reveal in Finder" button for Home Directory

* only enable for `USE_SDL`
2022-08-04 17:35:40 +02:00
bslenul 75ff5409f4 Switch broadcast region for San Francisco Rush 2049 and Sega Smash Pack - Volume 1 2022-07-25 11:26:12 +02:00
Flyinghead 642fad9a6e cfg: per-game settings must be deleted when changed back to standard
When a per-game setting is the same as the standard one, it is ignored
and not saved to emu.cfg. However the previously saved per-game setting
wasn't deleted, making it impossible to revert.

Issue #653
2022-07-25 11:25:42 +02:00
GABO1423 5ae7ac3eca (UWP) Add Additional Rescap Capabilities 2022-07-22 18:13:11 +02:00
Edward Li 885862a45e Get writable log path for macOS also 2022-07-22 18:12:43 +02:00
Edward Li 9b751fced8 NSLog with UTF-8, better color handling 2022-07-22 18:12:43 +02:00
Flyinghead 76bf574668 gl,gl4: disable anisotropic filtering if not linear
Issue #695
2022-07-15 20:36:29 +02:00
Edward Li c77c3ab015 DRY 2022-07-09 11:46:27 +02:00
Edward Li 8acd81cc43 Add MacPorts as alternative link 2022-07-09 11:46:27 +02:00
Enrique Santos c0e52b9a1a load game: destroy old maple devices before create call 2022-07-08 20:38:16 +02:00
Flyinghead 0840da1bd5 sdl: fix inverted axis detection 2022-07-08 20:36:20 +02:00
vkedwardli 852df89f93 [macOS] Handle Quit menu item properly (#684)
* [macOS] Handle Quit menu item properly

* cleanup
2022-07-05 14:37:28 +02:00
vkedwardli b5eb8694f6 macOS Breakpad (#683)
* Breakpad.framework and dump_syms

* Use ExceptionHandler manually instead of using public methods from the framework

* Change macOS buildType to RelWithDebInfo and enable building Breakpad framework

* Enable symbol upload on GitHub runner

* Compile Breakpad directly instead of embedding the Breakpad.framework

* Print minidump location also

* Ignore `EXC_MASK_BAD_ACCESS` again
2022-07-05 14:36:21 +02:00
Flyinghead f4986008fe jvs: fix 86-request decoding
Fixes kingrt66 inputs when networked
Issue #673
2022-07-05 14:34:57 +02:00
Flyinghead d6644c4935 lr: terminate emu during deinit on android
Issue #566 is for linux only, not android
2022-07-03 18:38:59 +02:00
Flyinghead 5bb8c86903 uwp: force windows sdk version to one compatible with current xbox fw
Fixes error at install: The package requires OS version 10.0.22621.0 or
higher on the Windows.Universal device family. The device is currently
running OS version 10.0.22000.4970.
2022-07-01 12:16:30 +02:00
vkedwardli a659b57e63 Install Vulkan SDK in generate_xcode_project.command (#678) 2022-06-30 14:11:26 +02:00
vkedwardli 44e96c544b Use source_group to create folder hierarchy for Xcode project (#679) 2022-06-30 14:10:15 +02:00
scribam 0a5b8891a8 android: update gradle 2022-06-30 14:09:20 +02:00
Flyinghead 6a5db32d5d don't protect RTT textures vram
Fixes Spikers Battle RTT texture spurious update before use
(transitions)
2022-06-27 13:37:22 +02:00
Flyinghead b0f3e065be ui: wrong scaling after imgui driver reset
ImGuiStyle::ScaleAllSizes() is cumulative so reset style before calling
it
Issue #676
2022-06-27 13:32:30 +02:00
Flyinghead fe895211c1 ui: reset imgui driver before creating new one
Possible fix for Issue #676
2022-06-26 15:23:30 +02:00
Flyinghead 907131b7f5 allow ForceWindowsCE option to be used in per-game config
Issue #252
2022-06-24 13:27:21 +02:00
Flyinghead 76508146ae cheats: only apply widescreen cheat if current value is expected
Issue  #180
2022-06-24 11:47:24 +02:00
vkedwardli 867b519a2b [macOS] Fix imagemagick not found on GitHub runners (#674)
disable dep check for brew reinstall
2022-06-21 09:50:05 +02:00
Flyinghead 74852520dc maxspeed: allow use of per-game network settings
Issue #671
2022-06-20 20:56:53 +02:00
Flyinghead faec4d8e50 gl: always use int arithmetic in palette index glsl calculation 2022-06-20 20:52:15 +02:00
Flyinghead d2aca1d621 savestate: overflow crash when serializing 2022-06-20 20:49:09 +02:00
Flyinghead 05961ac883 android build fix 2022-06-11 13:41:44 +02:00
flyinghead afd07c25ba pvr: store tex address in render context. texture cache refactoring
Store FT_W_SOF1 and FT_W_CTRL in render context since they can be
modified before render end. New tentative fix for vf4 water reflection
flashing black during netplay.
Refactor texture cache to use constructors. RTT code moved from
renderers.
Partial revert of ddcd3861d3
2022-06-11 13:24:22 +02:00
flyinghead 7ab92d88b1 msvc x86 build fix 2022-06-10 17:57:53 +02:00
flyinghead 3780299803 win32 raw api: user-friendly names for devices
Issue #664
2022-06-10 17:20:29 +02:00
flyinghead d78bb9ed3f don't list hidden folders and files on windows. Better parent dir prompt
Issue #666
2022-06-10 15:29:28 +02:00
Flyinghead b5f1552ed8 elan: don't crash on invalid texture xfer size
Issue #647: fixes initdv3jb area conquered crash
2022-06-06 15:54:25 +02:00
Gabriel Morazán 917cc7f27c Readme Updates. (#659)
* Update Reicast Link
2022-06-05 17:32:59 +02:00
Gabriel Morazán 2327e73ee7 (README) Update Xbox Section 2022-06-02 18:11:49 +02:00
Gabriel Morazán 397ddef68c (Libretro) Actually allow DX11 only cores.
Simple build fix.
2022-06-02 18:11:49 +02:00
Gabriel Morazán 3ec7f293ee (Libretro) Allow a DX11 only core to be built. (#657)
Main use case is Xbox systems.
2022-06-01 22:27:51 +02:00
flyinghead 26c8e8dab8 dx11 oit: naomi2 regression. Tr modvols shader needs divPosZ too 2022-06-01 19:26:56 +02:00
Flyinghead fdcea88519 gl4: wrong depth for transparent polys with native depth interp
Issue #630
2022-06-01 19:26:56 +02:00
flyinghead bf6c73060b native depth interpolation option to help AMD gpus
When enabled, set 1/z in pos.w and use native interpolation for colors,
UV and depth.
Get rid of manual modvol clipping in dx11.
2022-06-01 19:26:56 +02:00
Flyinghead ddcd3861d3 ggpo: don't protect rtt texture vram if ggpo is enabled
tentative fix for flashing water reflection texture in vf4 during
netplay
2022-05-31 17:42:42 +02:00
Flyinghead 971d47eb42 sdl: SDL_QuitSubSystem() on exit
Tentative fix for issue #654
2022-05-31 17:42:42 +02:00
Enrique Santos 13bd42bdab chat: disable window timeout after you respond to message 2022-05-30 16:15:44 +02:00
Flyinghead 71ac212dc7 elan: disable texture for vertices without UV coordinates
Fixes initial D white transparent quad at start of race
2022-05-30 16:15:15 +02:00
Flyinghead 2319a00c4f vk: bump moltenvk to 1.3.211.0 2022-05-29 13:35:22 +02:00
Flyinghead 1268077f6b cheat: missing cheat value in constructor
Fixes vf4tuned dimm check cheat writing random value (SH4 exception,
boot loop)
2022-05-29 13:30:06 +02:00
vkedwardli 5c579de459 Enable Texture Upscaling on macOS (#645)
* Compile a universal libomp
* static linking OpenMP
2022-05-28 13:00:20 +02:00
Flyinghead 167faff1f3 vk: invalid lightgun crosshair if maple device A isn't a lightgun 2022-05-28 12:58:53 +02:00
Flyinghead 22ad95cbfe ios: diagonal DPad buttons. Pan between buttons. Help tip for menu
Add diagonal DPad buttons
Allow switching virtual button without lifting finger.
Display help tip on first startup about pausing/opening menu.
2022-05-27 18:32:55 +02:00
Flyinghead db8508cefc ios: update AltKit 2022-05-27 18:20:16 +02:00
Flyinghead 5ac0772a2a vk oit: out of pool memory with moltenvk during render to texture 2022-05-26 18:06:30 +02:00
Flyinghead e2c2d6606d Fix Dead or Alive 2: Limited Edition (JP) widescreen cheat
Issue #625
2022-05-26 17:54:45 +02:00
Flyinghead 48361f58b6 vk oit: wrong temporary framebuffer dimensions 2022-05-25 16:44:24 +02:00
Enrique Santos dcb439f74a add ggpo chat window timeout 2022-05-23 11:42:11 +02:00
flyinghead 739a27be63 dx11 oit: render target and depth/stencil must have same dimensions
Fixes glitches during doa2 attract mode (depth/stencil missing).
2022-05-23 11:41:37 +02:00
Flyinghead e84cdce398 reios: flashrom read returns 0 on success. system id/timezone flash fix
flashrom read returns 0 on success, not size read.
Fixes Slave Zero (PAL) crash
2022-05-21 15:46:22 +02:00
Flyinghead af2fe242f9 flash: console id is checksummed 2022-05-18 14:58:21 +02:00
Flyinghead 0fb177bf85 reios: fix regression on many games due to 77a2bbbb
Jeremy McGrath
Skies of Arcadia
Speed Devils Online
Sydney 2000
Tech Romancer
Time Stalkers
Virtua Athlete 2000
Quake 3 (EU)
Climax Landers (JP)
Frame Gride
Pop'n'Music 1 & 2
Simple2000 2 & 3
2022-05-18 14:56:14 +02:00
Edward Li baab70c509 Rumble using MacBook's Taptic Engine (take 2) 2022-05-17 16:37:37 +02:00
scribam bc1c70bd1a ci: remove brew install libomp 2022-05-17 16:36:57 +02:00
scribam 12929c4571 openmp: use _OPENMP preprocessor, search openmp pkg unconditionally if enabled 2022-05-17 16:36:57 +02:00
Flyinghead 62522e4eb3 vk: naomi2 crash when lightModel is null
fixes crash at end of tutorial in kingrt66
2022-05-17 16:36:34 +02:00
Flyinghead 221060cc70 widescreen cheat for Dynamite Deka2 (JP), Zombie Revenge (naomi)
Better Dynamite Deka ex (naomi) widescreen cheat.
Courtesy of Goddamn Superhero
2022-05-16 13:06:38 +02:00
Flyinghead 58d1f7cee1 pvr: reset nextContext in Reset(). Use tactx_Alloc for direct fb render
Fix crash with multipass renders
Issue #634
2022-05-16 13:04:38 +02:00
Flyinghead 430256266f pvr: lightModels TA overrun on beach spikers
Better sizing of TA_context lists
2022-05-15 13:41:03 +02:00
Flyinghead f9e38b11d9 pvr: restore TA_context pool
fixes performance regression on android
2022-05-15 13:37:58 +02:00
Flyinghead 78e075546a libretro android build fix 2022-05-15 13:35:23 +02:00
jdgleaver 0e23b0bedd (libretro) Add option to detect and notifiy frontend of internal frame rate changes (60 <-> 30 <-> 20 fps, etc.)
Improves frame pacing in games with locked 30 fps and 20 fps frame rates
2022-05-13 17:13:25 +02:00
Flyinghead 903c768f7f vk oit: First frame after init wasn't displayed 2022-05-13 17:12:31 +02:00
Flyinghead cd22ba1a2b android: use WifiManager.MulticastLock to receive broadcast packets
In many cases, broadcast UDP packets can't be received on android unless
a MulticastLock is held.
2022-05-12 17:39:49 +02:00
flyinghead cce8cb8528 dx11 oit: missing TextureFiltering support
Issue #628
2022-05-11 19:16:31 +02:00
jdgleaver 6c6b447ea1 (libretro) Limit maximum number of audio samples that can be uploaded per call of retro_run() 2022-05-05 18:02:40 +02:00
Flyinghead 4554450d1d oit: add max layers and pixel buffer size options 2022-05-05 18:01:05 +02:00
Flyinghead a0d1dbf833 dx11: don't create the device in debug mode 2022-05-04 19:38:43 +02:00
Flyinghead a1a89df17f change vf4ft dimm check cheat. Don't apply cheat if not needed.
Fixes the SH4 exception seen with the previous cheat on some platforms.
Don't write memory if value is unchanged to avoid unnecessary protection
faults.
2022-05-04 10:30:35 +02:00
Flyinghead cf36384481 use nearest/point sampling to draw framebuffer if nearest is forced 2022-05-03 17:55:02 +02:00
flyinghead 9103371362 vk: increase descSet pool size for storage buffers and input attachments
Fixes out of host memory error on macOS
Issue #619
2022-05-03 17:49:46 +02:00
flyinghead 1b5ad34c8e dx11: (oit) use temporary render target for multipass
Render to temporary render target at end of pass and swap with regular
RT.
Fixes Tony Hawk 2 missing transparent geometry and character shadow.
Issue #618
2022-05-03 17:47:43 +02:00
Flyinghead c57e88850c lr: avoid crash when rewind is on
Issue #471
2022-05-01 19:22:22 +02:00
scribam 101a831534 cmake/macos: remove multitouch library 2022-05-01 12:34:43 +02:00
Flyinghead 3cc991fa4f oit: poly number/vertex id overflow
Use 17 bits for vertex id but substract first vtx index
Use 13 bits for poly number instead of 12
Panzer Front uses more than 4095 tr polys.
Issue #616
2022-05-01 12:33:53 +02:00
Flyinghead c348f4ccad allow a core without open gl to be built
Issue #515
2022-04-30 18:05:12 +02:00
Flyinghead 0181685d2f cheats: use software name as additional condition for widescreen
don't enable widescreen cheat for code veronica X
Issue #229
2022-04-30 12:08:36 +02:00
Flyinghead 39bb94dd55 jvs: don't scale ninja assault lightgun coordinates
Fixes reload issues (Issue #610)
2022-04-30 11:50:56 +02:00
Flyinghead 77a2bbbb8d reios: cancel gd dma int in g1_end_dma. drv_stat returns busy when busy
Cancel G1 DMA interrupt in G1_DMA_END (fixes MSR, Psychic Force, Pro
Pinball, Sega Swirl)
GET_DRV_STAT must return busy when drive is busy (fixes Hell Gate, Zero
Gunner)
Better named constants
2022-04-29 15:18:41 +02:00
Flyinghead afb0a80de1 pvr: autosort needs empty passes to be accounted for
Issue #612
2022-04-29 11:37:17 +02:00
Flyinghead 49932e02a6 gdrom: generate raw subcode 2022-04-27 14:32:53 +02:00
Flyinghead 990a4ad583 vk: ignore pipeline cache if loading fails 2022-04-27 14:30:03 +02:00
Flyinghead fc9e1e401b naomi: emulate midi ffb drive board response
needed for driving simulator
2022-04-27 14:28:58 +02:00
scribam 15ca7e82bd ci: fix java-version for actions/setup-java 2022-04-26 10:14:58 +02:00
Flyinghead 3b81bbcae5 naomi2: gmp diffuse/specular flags select vertex or model colors only
These flags shouldn't be used to disable diffuse/specular shading
Fixes road surface glitches in initdv3e (Usui map)
2022-04-21 13:55:09 +02:00
Flyinghead 902fc2cbe8 naomi: override Region settings if current region BIOS isn't found 2022-04-20 14:16:15 +02:00
Flyinghead 50f5dabf4a naomi2: use diffuse/specular color before light routing
fixes lion's jacket color and shun's face glitch (vf4)
2022-04-20 14:13:42 +02:00
scribam aa6c9e2106 msvc: fix linking issues in debug build 2022-04-17 13:24:37 +02:00
scribam 919fdb3594 ci: add distribution input to actions/setup-java@v3 2022-04-17 13:24:11 +02:00
Flyinghead c625cc68bf lr: increase vk descSet pool size. Insert card binding
vk: Use same descriptor set pool sizes for standalone and core
lr: bind "Insert Card" to L button (Naomi button 6)
lr: reset input descriptors when loading a new game
lr: don't reset maple devices in arcade mode: reloading eeprom cancels game settings
2022-04-17 13:23:16 +02:00
flyinghead d732140bf9 Merge pull request #595 from flyinghead/dev
Naomi 2 support
2022-04-16 14:24:49 +02:00
Flyinghead db525bd5db android: fix touchscreen on Retroid Pocket 2+
Unexpected event source for touchscreen events
2022-04-15 18:06:15 +02:00
Flyinghead 039c666247 more types.h clean up. better aica handler templates 2022-04-15 17:03:49 +02:00
Flyinghead ed5c24c281 arm64 build fix 2022-04-15 11:17:22 +02:00
Flyinghead f2f4010203 clean up types.h, refactoring 2022-04-14 11:34:45 +02:00
Flyinghead a9e261d280 simplify TA parsing 2022-04-13 20:36:52 +02:00
Flyinghead a710674cd4 gui: init once. reset ui driver when needed. android 120+ Hz support
ImGui is now initialized once at startup and shutdown before
terminating. graphics initialization is independent.
Move more imgui stuff into imgui drivers.
switch: set scaling on external screen to 1.4, same as xbox
UI scaling refactoring.
2022-04-13 18:06:19 +02:00
Flyinghead ddfc00ed9f Merge remote-tracking branch 'origin/master' into dev 2022-04-13 16:29:41 +02:00
Flyinghead ac71970561 don't save built-in cheats (vf4 dimm check) 2022-04-13 13:10:56 +02:00
Flyinghead fd50529d86 gl: (lr) black screen when vmu display is on
need to call glBindVertexArray(0) to avoid VAO being modified by the
frontend
2022-04-12 18:23:09 +02:00
Flyinghead 52d95e537c lr ci: disable switch build 2022-04-11 15:56:43 +02:00
Flyinghead 15b21fff2b vk: don't use anisotropic with nearest. Use linear mipmap filter
Issue #580
2022-04-11 13:35:48 +02:00
scribam f46bccfecd cmake: reunified dx9 files 2022-04-10 11:28:09 +02:00
Flyinghead 1f55973f72 libretro ci: add switch build 2022-04-10 11:27:37 +02:00
Flyinghead e0058c17ff lr: don't terminate emu on deinit. gl4: buffer wasn't released on term()
shared libraries containing gnuc unique symbols are never unloaded on
linux, and possibly other platforms. So don't terminate the emulator on
deinit and init it only once.
Issue #566

gl4: buffer not released on term() was causing crashes or black screen when restarted.
2022-04-05 14:53:47 +02:00
Flyinghead bf61f5cfe8 Merge remote-tracking branch 'origin/master' into dev 2022-04-04 12:11:10 +02:00
Flyinghead 8dcc25e1a9 ta: default base/offset color is white, not black
fixes black players in NHL 2K
2022-04-04 11:47:11 +02:00
Flyinghead a428167dc6 naomi network: alienfnt startup crash if not connected 2022-04-04 11:43:54 +02:00
Flyinghead 48e3a3eb68 aica: double arm clock speed
actual aica arm clock seems to be 22.5792 MHz, which means 512 cycles
per sample at 44.1 KHz (from 256)
fixes vf4 audio hiccup in character selection screen
2022-04-03 20:53:44 +02:00
Flyinghead a635fb3f77 test automation build fix, better exit 2022-04-03 20:46:50 +02:00
Flyinghead 320f679038 win32 build fix 2022-04-02 16:59:57 +02:00
Flyinghead 94c20ba29f elan: reset TA parser before loading state 2022-04-02 16:43:15 +02:00
Flyinghead 8baebcfb5b maxspeed networking. Store aw force feedback value 2022-04-02 16:41:52 +02:00
flyinghead 7fcce4a59b naomi network: ignore WSAECONNRESET. Longer timeout for client 2022-03-30 15:48:23 +02:00
Flyinghead 554ffcd08f naomi: use platform-independent network error codes (win32) 2022-03-30 14:13:02 +02:00
Flyinghead af0574c04e build fixes for msvc, ios and android 2022-03-27 15:57:01 +02:00
Flyinghead 6c38295d62 new naomi network protocol. vblank event. initd rumble support
new vblank event, used by cheats, lua and naomi net
new udp net protocol for naomi. rx/tx on vblank on emu thread.
input: rumble power configurable (Issue #158)
ui: rumble intensity slider, enable/disable upnp
aica: hook to consume midi out
decode midi out to simulate rumble for initd
upnp can now be disabled
2022-03-27 15:23:21 +02:00
Flyinghead 55e613fae5 widescreen cheats for gun spike, initdv3e, alpilotj, monkey ball
Courtesy of Esppiral
2022-03-21 17:51:31 +01:00
Flyinghead a5bad2b9b7 more naomi widescreen cheats. Fix vathlete 4-player mode
widescreen cheats for asndynmt, doa2m, slashout, spikers battle,
18wheeler, beach spikers. Courtesy of Esppiral
vathlete needs 2 I/O boards for 4-player mode
2022-03-20 17:49:50 +01:00
Flyinghead ebb251d8cf widescreen cheat for vf4tuned
Courtesy of Esppiral
2022-03-19 11:30:45 +01:00
Flyinghead 56768f2d3d naomi2: use TA parser. Use N2light directly with vk, dx11
Use TA parser to handle list type and clipping for Naomi 2 polys.
Pass all pass-throuch TA data to TA parser but stop on naomi2 command.
Set default projection matrix instead of identity (fixes Area conquered
screen invisible in initd).
Change N2Light and N2LightModel so they are usable in GLSL (vulkan) and
HLSL (dx11).
TA parser throws exception for unhandled param.
ta_vtx.cpp refactoring.
Support for subtractive lights (diffuse+specular). Used in some clubk
circuits.
Fix vulkan crash when direct FB render.
2022-03-16 17:28:45 +01:00
Flyinghead 5b3d36e081 naomi2: network support for clubk and initd
clubk: don't reverse handle by default
hotd2 doesn't have a proper game id or standard eeprom
2022-03-15 19:44:24 +01:00
Flyinghead ad08590197 vulkan: cache per-poly desc sets in map
avoid desc set pool exhaustion in per-triangle
2022-03-13 11:39:30 +01:00
Flyinghead 53b5588bda Merge remote-tracking branch 'origin/master' into dev 2022-03-13 11:01:27 +01:00
Flyinghead 1015a8c098 naomi2: vulkan support
oit: use #define instead of functions in GLSL
2022-03-12 17:56:46 +01:00
Flyinghead 27ddc215cc naomi2: boost lights by constant factor. simplify shaders 2022-03-08 17:38:29 +01:00
Flyinghead c11a6cd432 naomi2: partial gles2 compatibility
Issue #553
2022-03-07 20:32:08 +01:00
Flyinghead 3a62e432da switch: revert a92c2899c8
back to .obj instead of .o
2022-02-25 18:35:58 +01:00
Flyinghead 9c3f60c26c CI: windows-2019 for windows. devkita64:20220128 for switch 2022-02-25 18:30:28 +01:00
Flyinghead e5863920c4 naomi2: fix beach spiker crash
VUR vertices can also have environment mapping
2022-02-22 08:48:51 +01:00
Flyinghead 7f61b44d42 imgui: better drag scrolling code 2022-02-21 19:48:52 +01:00
Flyinghead a5660fa2b4 missing changes from previous commit 2022-02-18 17:40:00 +01:00
Flyinghead ecc03e3ebc naomi: use boot rom id to configure eeprom
Make eeprom from scratch if it doesn't exist based on boot id info.
Override eeprom settings to make game happy
Change region to supported one
Get rid of per-rom region info in rom list
New option to configure Naomi games in free play
2022-02-18 17:35:20 +01:00
Flyinghead a92c2899c8 switch build: cmake is now producing .o instead of .obj 2022-02-18 16:42:05 +01:00
Flyinghead af4638e83f naomi2: fix another initdv2 end of race crash 2022-02-18 16:40:26 +01:00
Flyinghead cecf1a5497 naomi2: fix initdv2 end of race crash 2022-02-17 18:31:20 +01:00
Flyinghead f2374982b8 pvr: don't merge polys with != palette. 2nd pass sometimes ignored
polys with different palette index shouldn't be merged.
If a pass isn't using any opaque, it can't be found. Fall back to using
the transparent or punch-through list in this case.
2022-02-17 18:30:29 +01:00
Flyinghead d736dd027d naomi2: initd card support. lua: fix multi-threading crash
initial d card reader support. insert card button.
lua: use mutex to enforce thread-safety
2022-02-16 19:02:04 +01:00
Flyinghead 214db9e0b1 gl4: depth pass need texture and UV for punch-through polys 2022-02-15 17:18:32 +01:00
Flyinghead 3bbc89afc9 dx11: fix crash with modvols 2022-02-15 17:16:45 +01:00
Flyinghead e35ccbbb18 naomi2: force region for some roms. elan clean up 2022-02-15 17:15:44 +01:00
flyinghead 8d071bf4ea naomi2: dx11 support. fix ambient color. no depth write in per-strip
dx11: naomi2 support
n2: ambient color was swapping red and blue
gl, dx11: don't write depth in per-strip to avoid missing geometry,
prefer wrong depth order/blending for now
optimize naomi2 per-triangle sorting
2022-02-13 21:01:45 +01:00
Flyinghead a14086d484 naomi2: shader error in gles. Invert clubkart wheel axis 2022-02-11 19:06:58 +01:00
Flyinghead 20d25059bf naomi2: remove geom shader. Merge transparent polys. bump mapping fix.
elan: Get rid of geometry shader and do geometry clipping manually.
pvr: Aggressively merge transparent polys in per-triangl and OIT mode, duplicating the last vertex to merge opposite cull mode strips.
gl4: reset OIT pointers in final shader. No need for clear pass.
gl4: alternate between 2 buffers for verts.index/tr poly params.
gl4: use gl_VertexID + poly number for poly index.
gl: new GlBuffer class.
2022-02-11 15:54:18 +01:00
Flyinghead ccee7162bc naomi2: soulsurfer inputs, 2-volume UV, wrong TA parser selected
TAParserDX was used for pass-through TA data. Fixes health bar color in
vf4 and dust color in kingrt66.
2-volume missing u1/v1. Fixes clubk shadows.
2022-02-08 10:32:56 +01:00
Flyinghead debbae6ab1 naomi2: elan v10 emulation. texture dma xfers. 2-volume support
emulate elan v10 (fixes modvol in vf4, initd, beachspiker, wldrider)
wrong color order for model and vtx color
model param override xor support
improved light direction precision. Angle attenuation algo change
get rid of alpha light and modifier volume hacks
texture dma xfer from main and elan ram
gl4: use geometry only vtx and geom shaders for depth pass
2-volume support
2022-02-05 14:50:12 +01:00
Flyinghead 2c6f01ae38 naomi2: kingrt66 wiper button. initd gear up/down
kingrt66: map wiper button, remap shift H and R
initd: map gear up and down
wldrider: remap push and pull
2022-02-05 14:29:01 +01:00
Flyinghead 0362fd1079 naomi2: disable elan when net rollbacking, optimizations. ggpo: RTT fix
n2: do not process elan commands during ggpo rollbacks.
n2: Cache model colors to avoid unpacking for each vtx
pvr: merge equivalent polys with different culling by duping a vtx
pvr: fix crash during direct FB render
pvr: use correct color ordering for naomi2. Use identify matrix for null matrix pointers
ggpo: do not signal end of frame on a render to texture
2022-02-01 17:37:54 +01:00
Flyinghead 38765dc89a pvr: fix multipass. naomi2: constant color shading.
pvr: link multipass TA contexts. Each pass has its own.
pvr: get rid of context pool
naomi2: constant color shading. Use model diffuse and specular
selection. Don't use vtx color for offset color.
naomi2: pseudo-parallel lights fix
naomi2: pass-through TA data needs forced list type. Terminate with
end-of-list
enable RTT copy to vram for Beach Spikers
2022-01-31 20:40:09 +01:00
Flyinghead 78306b3c12 ggpo: memory leak in free_buffer 2022-01-30 12:39:00 +01:00
Flyinghead e51a291195 ggpo: wrong elan ram offset calculation 2022-01-30 12:39:00 +01:00
flyinghead d551848a9b dummy commit 2022-01-29 19:39:08 +01:00
Flyinghead fe6247dded cheats: iOS build fix 2022-01-29 18:40:19 +01:00
Flyinghead 5fb8b458bb pvr: use TA_OL_BASE instead of PARAM_BASE/TA_ISP_BASE to id TA context
Writes current TA_OL_BASE to all tiles OPB block. Read from region array
at render time to identify context.
Fixes vf4 water reflections RTT
get rid of dump_frame/read_frame
2022-01-29 18:39:38 +01:00
Flyinghead 340c55c570 build fix 2022-01-28 22:30:07 +01:00
Flyinghead de1322b928 naomi2: Fix T&L matrix. vmem elan ram support.
Fix T&L matrix (wild riders)
Open GL support for normal/light matrix
handle elan RAM in vmem
2022-01-28 21:24:30 +01:00
Flyinghead 010d257b69 naomi2: vf4tuned cheat/hack to skip DIMM fw version check 2022-01-28 20:02:07 +01:00
Flyinghead e5d517dad2 use platform.isConsole(), platform.isNaomi(), ... 2022-01-27 17:52:19 +01:00
Flyinghead 965dea5fe6 test fix 2022-01-27 16:44:37 +01:00
Flyinghead 1ffcc75031 naomi2: implement SB_ISTNRM for clxb. serialize elan state 2022-01-27 16:40:12 +01:00
Flyinghead e084cc9a3a jvs: set received jvs message trail to zero
fixes sh4 crash during naomi boot
2022-01-27 15:50:44 +01:00
Flyinghead 6ed78d1202 another GL_CLIP_DISTANCE0 build fix 2022-01-26 22:37:38 +01:00
Flyinghead 270eaa1452 GL_CLIP_DISTANCE1 undefined 2022-01-26 22:19:53 +01:00
Flyinghead e1038ea632 naomi2: fix regressions. 2-volume and bump mapping support WIP
optimize open gl uniforms
2022-01-26 22:15:10 +01:00
Flyinghead 8947100701 libretro: missing new param to gl4GetProgram 2022-01-25 15:43:30 +01:00
Flyinghead cb99e7d920 naomi2: do T&L on the gpu. bypass TA format. env mapping.
fix model/instance/matrix parsing
handle culling reversed model flag
geometry shader for near plane clipping
2022-01-25 15:37:04 +01:00
Flyinghead b048921c11 naomi2: fix clipping, parallel light direction, reset state on loadstate 2022-01-18 18:25:40 +01:00
Flyinghead 4335aa563f naomi2 WIP 2022-01-16 22:41:42 +01:00
252 changed files with 14466 additions and 6299 deletions

No files matched your search

+9 -5
View File
@@ -18,7 +18,7 @@ jobs:
matrix:
config:
- {name: i686-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release}
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode, destDir: osx, buildType: Release}
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode -DAPPLE_BREAKPAD=ON, destDir: osx, buildType: RelWithDebInfo}
- {name: apple-ios, os: macos-latest, shell: sh, cmakeArgs: -DCMAKE_SYSTEM_NAME=iOS -G Xcode, destDir: ios, buildType: Release}
- {name: x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -G Ninja, buildType: Release}
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja, buildType: Release}
@@ -30,8 +30,8 @@ jobs:
- name: Set up build environment (macOS)
run: |
brew update
brew install libao ldid libomp ninja pulseaudio
wget https://sdk.lunarg.com/sdk/download/1.3.204.1/mac/vulkansdk-macos-1.3.204.1.dmg
brew install libao ldid ninja pulseaudio
VULKAN_VER=1.3.211.0 && aria2c --parameterized-uri=true https://{sdk.lunarg.com/sdk/download/$VULKAN_VER/mac,distfiles.macports.org/MoltenVK}/vulkansdk-macos-$VULKAN_VER.dmg
hdiutil attach ./vulkansdk-macos-*.dmg
sudo /Volumes/vulkansdk-macos-*/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install
hdiutil detach /Volumes/vulkansdk-macos-*
@@ -67,6 +67,10 @@ jobs:
fetch-depth: 0
submodules: true
- name: Compile a universal OpenMP (macOS)
run: export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1; brew reinstall --build-from-source --formula ./shell/apple/libomp.rb
if: runner.os == 'macOS'
- uses: actions/cache@v3
with:
path: ${{ env.CCACHE_DIR }}
@@ -126,7 +130,7 @@ jobs:
shell: bash
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
- name: Upload symbols to S3
- name: Upload symbols to S3 (Windows-MinGW, macOS)
run: aws s3 sync symbols s3://flycast-symbols/${{ matrix.config.destDir }} --follow-symlinks
shell: bash
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' && matrix.config.name == 'x86_64-w64-mingw32' }}
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' && (matrix.config.name == 'x86_64-w64-mingw32' || matrix.config.name == 'apple-darwin') }}
+2 -1
View File
@@ -17,7 +17,8 @@ jobs:
- name: Setup Java JDK
uses: actions/setup-java@v3
with:
java-version: 1.8
distribution: 'temurin'
java-version: 8
- name: Setup Python
uses: actions/setup-python@v3
+2 -1
View File
@@ -14,7 +14,8 @@ jobs:
- name: Setup Java JDK
uses: actions/setup-java@v3
with:
java-version: 1.8
distribution: 'temurin'
java-version: 8
- name: Setup Python
uses: actions/setup-python@v3
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
- name: CMake
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_SYSTEM_PROCESSOR=AMD64 -DCMAKE_CROSSCOMPILING=OFF -DUSE_VULKAN=OFF -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.22000.0 -DCMAKE_SYSTEM_PROCESSOR=AMD64 -DCMAKE_CROSSCOMPILING=OFF -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake
cmake --build build --config Release --parallel 2
shell: cmd
+13
View File
@@ -52,10 +52,16 @@ include:
- project: 'libretro-infrastructure/ci-templates'
file: '/android-cmake.yml'
################################## CONSOLES ################################
# Nintendo Switch
# - project: 'libretro-infrastructure/ci-templates'
# file: '/libnx-static.yml'
# Stages for building
stages:
- build-prepare
- build-shared
# - build-static
##############################################################################
#################################### STAGES ##################################
@@ -116,3 +122,10 @@ android-x86:
extends:
- .libretro-android-cmake-x86
- .core-defs-android
################################### CONSOLES #################################
# Nintendo Switch
#libretro-build-libnx-aarch64:
# extends:
# - .libretro-libnx-static-retroarch-master
# - .core-defs
+141 -43
View File
@@ -19,6 +19,7 @@ option(USE_VULKAN "Build with Vulkan support" ON)
option(LIBRETRO "Build libretro core" OFF)
option(USE_OPENGL "Use Open GL API" ON)
option(USE_VIDEOCORE "RPI: use the legacy Broadcom GLES libraries" OFF)
option(APPLE_BREAKPAD "macOS: Build breakpad client and dump symbols" OFF)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/shell/cmake")
@@ -119,7 +120,7 @@ elseif(LIBRETRO)
else()
target_link_libraries(${PROJECT_NAME} PRIVATE "-lGLESv2")
endif()
else()
elseif(USE_OPENGL)
target_compile_definitions(${PROJECT_NAME} PRIVATE HAVE_OPENGL)
if(APPLE)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-framework,OpenGL")
@@ -144,6 +145,7 @@ endif()
if(WINDOWS_STORE)
set(USE_OPENGL OFF)
set(USE_VULKAN OFF)
target_compile_features(${PROJECT_NAME} PRIVATE c_std_11 cxx_std_17)
else()
target_compile_features(${PROJECT_NAME} PRIVATE c_std_11 cxx_std_11)
@@ -198,23 +200,84 @@ if(NOT LIBRETRO)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC breakpad_client)
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_BREAKPAD)
elseif(APPLE AND NOT IOS AND APPLE_BREAKPAD)
target_sources(${PROJECT_NAME} PRIVATE
core/deps/breakpad/src/client/minidump_file_writer-inl.h
core/deps/breakpad/src/client/minidump_file_writer.cc
core/deps/breakpad/src/client/minidump_file_writer.h
core/deps/breakpad/src/client/mac/handler/breakpad_nlist_64.cc
core/deps/breakpad/src/client/mac/handler/breakpad_nlist_64.h
core/deps/breakpad/src/client/mac/handler/dynamic_images.cc
core/deps/breakpad/src/client/mac/handler/dynamic_images.h
core/deps/breakpad/src/client/mac/handler/exception_handler.cc
core/deps/breakpad/src/client/mac/handler/exception_handler.h
core/deps/breakpad/src/client/mac/handler/minidump_generator.cc
core/deps/breakpad/src/client/mac/handler/minidump_generator.h
core/deps/breakpad/src/client/mac/handler/protected_memory_allocator.cc
core/deps/breakpad/src/client/mac/handler/protected_memory_allocator.h
core/deps/breakpad/src/client/mac/crash_generation/ConfigFile.h
core/deps/breakpad/src/client/mac/crash_generation/ConfigFile.mm
core/deps/breakpad/src/client/mac/crash_generation/client_info.h
core/deps/breakpad/src/client/mac/crash_generation/crash_generation_client.h
core/deps/breakpad/src/client/mac/crash_generation/crash_generation_client.cc
core/deps/breakpad/src/common/convert_UTF.cc
core/deps/breakpad/src/common/convert_UTF.h
core/deps/breakpad/src/common/md5.cc
core/deps/breakpad/src/common/string_conversion.cc
core/deps/breakpad/src/common/string_conversion.h
core/deps/breakpad/src/common/mac/file_id.cc
core/deps/breakpad/src/common/mac/file_id.h
core/deps/breakpad/src/common/mac/MachIPC.mm
core/deps/breakpad/src/common/mac/MachIPC.h
core/deps/breakpad/src/common/mac/bootstrap_compat.cc
core/deps/breakpad/src/common/mac/bootstrap_compat.h
core/deps/breakpad/src/common/mac/macho_id.cc
core/deps/breakpad/src/common/mac/macho_id.h
core/deps/breakpad/src/common/mac/macho_utilities.cc
core/deps/breakpad/src/common/mac/macho_utilities.h
core/deps/breakpad/src/common/mac/macho_walker.cc
core/deps/breakpad/src/common/mac/macho_walker.h
core/deps/breakpad/src/common/mac/string_utilities.cc
core/deps/breakpad/src/common/mac/string_utilities.h
)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/breakpad/src)
target_compile_definitions(${PROJECT_NAME} PRIVATE USE_BREAKPAD)
add_custom_target(dump_syms COMMAND xcodebuild -project ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj -target dump_syms -configuration Release CONFIGURATION_BUILD_DIR=${CMAKE_CURRENT_SOURCE_DIR}/build/breakpad)
ADD_DEPENDENCIES(${PROJECT_NAME} dump_syms)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND sleep 20
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build/breakpad/dump_syms
-a x86_64
-g ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/Flycast.app.dSYM
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/Flycast.app/Contents/MacOS/Flycast > Flycast.sym
COMMAND mkdir -p ../symbols/Flycast/`head -1 Flycast.sym | awk '{ print $4 }'`
COMMAND mv Flycast.sym ../symbols/Flycast/`head -1 Flycast.sym | awk '{ print $4 }'`
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build/breakpad/dump_syms
-a arm64
-g ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/Flycast.app.dSYM
${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/Flycast.app/Contents/MacOS/Flycast > Flycast.sym
COMMAND mkdir -p ../symbols/Flycast/`head -1 Flycast.sym | awk '{ print $4 }'`
COMMAND mv Flycast.sym ../symbols/Flycast/`head -1 Flycast.sym | awk '{ print $4 }'`
)
endif()
endif()
find_package(OpenMP)
if(OpenMP_CXX_FOUND AND NOT APPLE AND USE_OPENMP)
if(MINGW)
target_link_libraries(${PROJECT_NAME} PRIVATE "-static -lgomp -lpthread")
target_compile_options(${PROJECT_NAME} PRIVATE -fopenmp)
elseif(ANDROID)
# Reference: https://android.googlesource.com/platform/ndk/+/refs/heads/master/tests/device/openmp/CMakeLists.txt
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_OPTIONS -fopenmp)
target_link_libraries(${PROJECT_NAME} PRIVATE -fopenmp -static-openmp)
else()
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
if(USE_OPENMP)
find_package(OpenMP)
if(OpenMP_CXX_FOUND)
if(MINGW)
target_link_libraries(${PROJECT_NAME} PRIVATE "-static -lgomp -lpthread")
target_compile_options(${PROJECT_NAME} PRIVATE -fopenmp)
elseif(ANDROID)
# Reference: https://android.googlesource.com/platform/ndk/+/refs/heads/master/tests/device/openmp/CMakeLists.txt
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_OPTIONS -fopenmp)
target_link_libraries(${PROJECT_NAME} PRIVATE -fopenmp -static-openmp)
elseif(APPLE)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX -static-openmp)
else()
target_link_libraries(${PROJECT_NAME} PRIVATE OpenMP::OpenMP_CXX)
endif()
endif()
else()
target_compile_definitions(${PROJECT_NAME} PRIVATE TARGET_NO_OPENMP)
endif()
option(BUILD_SHARED_LIBS "Build shared library" OFF)
@@ -245,18 +308,11 @@ if(NOT LIBRETRO)
endif()
if(NOT ANDROID AND NOT IOS)
if(APPLE)
# Patch SDL
execute_process(COMMAND git apply -p1 ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/patches/SDL.patch
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/core/deps/SDL)
else()
if(NOT APPLE)
find_package(SDL2)
endif()
if(NOT SDL2_FOUND)
add_subdirectory(core/deps/SDL EXCLUDE_FROM_ALL)
if(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 4)
target_compile_definitions(SDL2-static PRIVATE HAVE_LIBC)
endif()
set(SDL2_FOUND 1)
endif()
@@ -549,15 +605,18 @@ if(LIBRETRO)
core/deps/libretro-common/compat/fopen_utf8.c
core/deps/libretro-common/compat/compat_strcasestr.c
core/deps/libretro-common/file/retro_dirent.c
core/deps/libretro-common/string/stdstring.c
core/deps/libretro-common/glsm/glsm.c
core/deps/libretro-common/glsym/rglgen.c)
if(ANDROID OR USE_GLES)
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_es3.c)
elseif(USE_GLES2)
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_es2.c)
else()
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_gl.c)
core/deps/libretro-common/string/stdstring.c)
if(USE_OPENGL)
target_sources(${PROJECT_NAME} PRIVATE
core/deps/libretro-common/glsm/glsm.c
core/deps/libretro-common/glsym/rglgen.c)
if(ANDROID OR USE_GLES)
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_es3.c)
elseif(USE_GLES2)
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_es2.c)
else()
target_sources(${PROJECT_NAME} PRIVATE core/deps/libretro-common/glsym/glsym_gl.c)
endif()
endif()
target_sources(${PROJECT_NAME} PRIVATE
shell/libretro/audiostream.cpp
@@ -595,6 +654,7 @@ if(NOT LIBRETRO)
endif()
target_sources(${PROJECT_NAME} PRIVATE
core/hw/hwreg.h
core/hw/aica/aica.cpp
core/hw/aica/aica.h
core/hw/aica/aica_if.cpp
@@ -620,7 +680,6 @@ target_sources(${PROJECT_NAME} PRIVATE
core/hw/arm7/arm7_rec.cpp
core/hw/arm7/arm7_rec.h
core/hw/arm7/arm-new.h
core/hw/arm7/vbaARM.cpp
core/hw/bba/bba.h
core/hw/bba/bba.cpp
core/hw/bba/rtl8139c.h
@@ -676,6 +735,11 @@ target_sources(${PROJECT_NAME} PRIVATE
core/hw/naomi/naomi_roms.cpp
core/hw/naomi/naomi_roms.h
core/hw/naomi/naomi_roms_input.h
core/hw/naomi/card_reader.h
core/hw/naomi/card_reader.cpp
core/hw/pvr/elan.cpp
core/hw/pvr/elan.h
core/hw/pvr/elan_struct.h
core/hw/pvr/helper_classes.h
core/hw/pvr/pvr.cpp
core/hw/pvr/pvr.h
@@ -696,7 +760,6 @@ target_sources(${PROJECT_NAME} PRIVATE
core/hw/pvr/ta.h
core/hw/pvr/ta_structs.h
core/hw/pvr/ta_vtx.cpp
core/hw/sh4/dyna
core/hw/sh4/dyna/blockmanager.cpp
core/hw/sh4/dyna/blockmanager.h
core/hw/sh4/dyna/decoder.cpp
@@ -711,12 +774,10 @@ target_sources(${PROJECT_NAME} PRIVATE
core/hw/sh4/dyna/ssa.h
core/hw/sh4/dyna/ssa_regalloc.h
core/hw/sh4/fsca-table.h
core/hw/sh4/interpr
core/hw/sh4/interpr/sh4_fpu.cpp
core/hw/sh4/interpr/sh4_interpreter.cpp
core/hw/sh4/interpr/sh4_opcodes.cpp
core/hw/sh4/interpr/sh4_opcodes.h
core/hw/sh4/modules
core/hw/sh4/modules/bsc.cpp
core/hw/sh4/modules/ccn.cpp
core/hw/sh4/modules/ccn.h
@@ -920,7 +981,9 @@ if(USE_OPENGL)
core/rend/gles/gltex.cpp
core/rend/gles/quad.cpp
core/rend/gles/postprocess.cpp
core/rend/gles/postprocess.h)
core/rend/gles/postprocess.h
core/rend/gles/naomi2.cpp
core/rend/gles/naomi2.h)
if(NOT LIBRETRO)
target_sources(${PROJECT_NAME} PRIVATE
@@ -935,7 +998,9 @@ if(USE_OPENGL)
core/rend/gl4/abuffer.cpp
core/rend/gl4/gl4.h
core/rend/gl4/gldraw.cpp
core/rend/gl4/gles.cpp)
core/rend/gl4/gles.cpp
core/rend/gl4/gl4naomi2.cpp
core/rend/gl4/gl4naomi2.h)
endif()
endif()
@@ -1047,8 +1112,32 @@ if(USE_VULKAN)
endif()
if(WIN32 AND NOT LIBRETRO AND NOT WINDOWS_STORE)
add_subdirectory(core/rend/dx9)
target_link_libraries(${PROJECT_NAME} PRIVATE dx9renderer)
set(REND_DX9_FILES
core/rend/dx9/d3d_overlay.h
core/rend/dx9/d3d_overlay.cpp
core/rend/dx9/d3d_renderer.h
core/rend/dx9/d3d_renderer.cpp
core/rend/dx9/d3d_shaders.h
core/rend/dx9/d3d_shaders.cpp
core/rend/dx9/d3d_texture.h
core/rend/dx9/d3d_texture.cpp
core/rend/dx9/dx9_driver.h
core/rend/dx9/dxcontext.cpp
core/rend/dx9/dxcontext.h
core/rend/dx9/imgui_impl_dx9.h
core/rend/dx9/imgui_impl_dx9.cpp)
target_sources(${PROJECT_NAME} PRIVATE ${REND_DX9_FILES})
if(NOT MINGW)
set_source_files_properties(${REND_DX9_FILES} PROPERTIES INCLUDE_DIRECTORIES "$ENV{DXSDK_DIR}/Include")
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
target_link_directories(${PROJECT_NAME} PUBLIC "$ENV{DXSDK_DIR}/Lib/x64")
else()
target_link_directories(${PROJECT_NAME} PUBLIC "$ENV{DXSDK_DIR}/Lib/x86")
endif()
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC d3d9 d3dx9)
endif()
if(WIN32)
@@ -1076,6 +1165,8 @@ if(WIN32)
core/rend/dx11/dx11context_lr.cpp
core/rend/dx11/dx11context_lr.h
core/rend/dx11/dx11_driver.h
core/rend/dx11/dx11_naomi2.cpp
core/rend/dx11/dx11_naomi2.h
core/rend/dx11/oit/dx11_oitbuffers.h
core/rend/dx11/oit/dx11_oitrenderer.cpp
core/rend/dx11/oit/dx11_oitshaders.cpp
@@ -1345,6 +1436,10 @@ if(NOT LIBRETRO)
MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0"
MACOSX_BUNDLE_BUNDLE_VERSION "1"
MACOSX_BUNDLE_COPYRIGHT "Copyright © 2019 Flycast contributors. All rights reserved."
XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf"
XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT[variant=RelWithDebInfo] "dwarf-with-dsym"
XCODE_ATTRIBUTE_CLANG_DEBUG_INFORMATION_LEVEL[variant=RelWithDebInfo] "line-tables-only"
XCODE_ATTRIBUTE_DEPLOYMENT_POSTPROCESSING[variant=RelWithDebInfo] YES
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME "AppIcon"
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.flyinghead.Flycast"
BUILD_WITH_INSTALL_RPATH TRUE
@@ -1354,17 +1449,17 @@ if(NOT LIBRETRO)
find_library(AUDIO_UNIT_LIBRARY AudioUnit)
find_library(FOUNDATION_LIBRARY Foundation)
find_library(AUDIO_TOOLBOX_LIBRARY AudioToolbox)
find_library(MULTITOUCH_SUPPORT_LIBRARY MultitouchSupport /System/Library/PrivateFrameworks)
find_library(OPENGL_LIBRARY OpenGL)
find_library(IOSURFACE_LIBRARY IOSurface)
find_library(MULTITOUCH_SUPPORT_LIBRARY MultitouchSupport /System/Library/PrivateFrameworks)
target_link_libraries(${PROJECT_NAME} PRIVATE
${AUDIO_UNIT_LIBRARY}
${FOUNDATION_LIBRARY}
${AUDIO_TOOLBOX_LIBRARY}
${MULTITOUCH_SUPPORT_LIBRARY}
${OPENGL_LIBRARY}
${IOSURFACE_LIBRARY})
${IOSURFACE_LIBRARY}
${MULTITOUCH_SUPPORT_LIBRARY})
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy "$ENV{VULKAN_SDK}/lib/libMoltenVK.dylib"
@@ -1403,7 +1498,7 @@ if(NOT LIBRETRO)
set_target_properties(${PROJECT_NAME} PROPERTIES RESOURCE "${ResourceFiles}")
else()
target_sources(${PROJECT_NAME} PRIVATE shell/windows/flycast.rc)
target_link_libraries(${PROJECT_NAME} PRIVATE dsound opengl32 winmm ws2_32 wsock32 xinput9_1_0)
target_link_libraries(${PROJECT_NAME} PRIVATE dsound opengl32 winmm ws2_32 wsock32 xinput9_1_0 cfgmgr32)
endif()
endif()
endif()
@@ -1469,3 +1564,6 @@ if(UNIX AND NOT APPLE AND NOT ANDROID AND NOT LIBRETRO)
)
endforeach()
endif()
file(GLOB_RECURSE SRC_FILES *.h *.cpp *.c *.cc *.mm)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SRC_FILES})
+13 -9
View File
@@ -7,7 +7,7 @@
![flycast logo](https://github.com/flyinghead/flycast/raw/master/shell/linux/flycast.png)
**Flycast** is a multi-platform Sega Dreamcast, Naomi and Atomiswave emulator derived from [**reicast**](https://reicast.com/).
**Flycast** is a multi-platform Sega Dreamcast, Naomi, Naomi 2, and Atomiswave emulator derived from [**reicast**](https://github.com/skmp/reicast-emulator).
Information about configuration and supported features can be found on [**TheArcadeStriker's flycast wiki**](https://github.com/TheArcadeStriker/flycast-wiki/wiki).
@@ -17,30 +17,34 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat.
### Flatpak (Linux)
1. [Set up Flatpak](https://www.flatpak.org/setup/)
1. [Set up Flatpak](https://www.flatpak.org/setup/).
2. Install Flycast from [Flathub](https://flathub.org/apps/details/org.flycast.Flycast)
2. Install Flycast from [Flathub](https://flathub.org/apps/details/org.flycast.Flycast):
`flatpak install -y org.flycast.Flycast`
3. Run Flycast
3. Run Flycast:
`flatpak run org.flycast.Flycast`
### Homebrew (MacOS)
1. [Set up Homebrew](https://brew.sh)
1. [Set up Homebrew](https://brew.sh).
2. Install Flycast via Homebrew
2. Install Flycast via Homebrew:
`brew install --cask flycast`
### Xbox One
### Xbox One/Series
Open [**gamr13's github page**](https://gamr13.github.io/) from your console.
#### Retail:
Open [**gamr13's github page**](https://gamr13.github.io/) from your Xbox console.
#### Dev Mode:
Grab the latest build from [**the builds page**](https://flyinghead.github.io/flycast-builds/), or the [**GitHub Actions**](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml). Then install it using the **Xbox Device Portal**.
### Binaries
Get fresh builds for your system [**on the builds page**](https://flyinghead.github.io/flycast-builds/).
**New:** Now automated test results are available as well.
**New:** Now automated test results are available as well.
+12
View File
@@ -82,6 +82,13 @@ s32 cfgLoadInt(const std::string& section, const std::string& key, s32 def)
return cfgdb.get_int(section, key, def);
}
int64_t cfgLoadInt64(const std::string& section, const std::string& key, int64_t def) {
return cfgdb.get_int64(section, key, def);
}
void cfgSaveInt64(const std::string& section, const std::string& key, int64_t value) {
cfgdb.set_int64(section, key, value);
}
void cfgSaveBool(const std::string& section, const std::string& key, bool value)
{
cfgSaveStr(section, key, value ? "yes" : "no");
@@ -112,6 +119,11 @@ void cfgDeleteSection(const std::string& section)
cfgdb.delete_section(section);
}
void cfgDeleteEntry(const std::string& section, const std::string& key)
{
cfgdb.delete_entry(section, key);
}
void cfgSetAutoSave(bool autoSave)
{
::autoSave = autoSave;
+3
View File
@@ -5,6 +5,8 @@
bool cfgOpen();
s32 cfgLoadInt(const std::string& section, const std::string& key, s32 def);
void cfgSaveInt(const std::string& section, const std::string& key, s32 value);
int64_t cfgLoadInt64(const std::string& section, const std::string& key, int64_t def);
void cfgSaveInt64(const std::string& section, const std::string& key, int64_t value);
std::string cfgLoadStr(const std::string& section, const std::string& key, const std::string& def);
void cfgSaveStr(const std::string& section, const std::string& key, const std::string& value);
void cfgSaveBool(const std::string& section, const std::string& key, bool value);
@@ -17,3 +19,4 @@ bool ParseCommandLine(int argc, char *argv[]);
void cfgSetAutoSave(bool autoSave);
bool cfgHasSection(const std::string& section);
void cfgDeleteSection(const std::string& section);
void cfgDeleteEntry(const std::string& section, const std::string& key);
+28
View File
@@ -24,6 +24,14 @@ int ConfigEntry::get_int()
}
}
int64_t ConfigEntry::get_int64()
{
int base = 10;
if (strstr(this->value.c_str(), "0x") != nullptr)
base = 16;
return (int64_t)strtoll(this->value.c_str(), nullptr, base);
}
bool ConfigEntry::get_bool()
{
if (stricmp(this->value.c_str(), "yes") == 0 ||
@@ -158,6 +166,19 @@ int ConfigFile::get_int(const std::string& section_name, const std::string& entr
}
}
int64_t ConfigFile::get_int64(const std::string& section_name, const std::string& entry_name, int64_t default_value)
{
ConfigEntry* entry = this->get_entry(section_name, entry_name);
if (entry == NULL)
{
return default_value;
}
else
{
return entry->get_int64();
}
}
bool ConfigFile::get_bool(const std::string& section_name, const std::string& entry_name, bool default_value)
{
ConfigEntry* entry = this->get_entry(section_name, entry_name);
@@ -188,6 +209,13 @@ void ConfigFile::set_int(const std::string& section_name, const std::string& ent
this->set(section_name, entry_name, str_value.str(), is_virtual);
}
void ConfigFile::set_int64(const std::string& section_name, const std::string& entry_name, int64_t value, bool is_virtual)
{
std::stringstream str_value;
str_value << value;
this->set(section_name, entry_name, str_value.str(), is_virtual);
}
void ConfigFile::set_bool(const std::string& section_name, const std::string& entry_name, bool value, bool is_virtual)
{
std::string str_value = (value ? "yes" : "no");
+3
View File
@@ -11,6 +11,7 @@ struct ConfigEntry {
const std::string& get_string() const;
int get_int();
bool get_bool();
int64_t get_int64();
};
struct ConfigSection {
@@ -41,10 +42,12 @@ struct ConfigFile {
/* getting values */
std::string get(const std::string& section_name, const std::string& entry_name, const std::string& default_value = "");
int get_int(const std::string& section_name, const std::string& entry_name, int default_value = 0);
int64_t get_int64(const std::string& section_name, const std::string& entry_name, int64_t default_value = 0);
bool get_bool(const std::string& section_name, const std::string& entry_name, bool default_value = false);
/* setting values */
void set(const std::string& section_name, const std::string& entry_name, const std::string& value, bool is_virtual = false);
void set_int(const std::string& section_name, const std::string& entry_name, int value, bool is_virtual = false);
void set_int64(const std::string& section_name, const std::string& entry_name, int64_t value, bool is_virtual = false);
void set_bool(const std::string& section_name, const std::string& entry_name, bool value, bool is_virtual = false);
void delete_section(const std::string& section_name);
+9 -1
View File
@@ -17,6 +17,7 @@
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "option.h"
#include "network/naomi_network.h"
namespace config {
@@ -36,6 +37,7 @@ Option<bool> ForceWindowsCE("Dreamcast.ForceWindowsCE");
Option<bool> AutoLoadState("Dreamcast.AutoLoadState");
Option<bool> AutoSaveState("Dreamcast.AutoSaveState");
Option<int> SavestateSlot("Dreamcast.SavestateSlot");
Option<bool> ForceFreePlay("ForceFreePlay", true);
// Sound
@@ -93,11 +95,13 @@ Option<int> MaxThreads("pvr.MaxThreads", 3);
Option<int> AutoSkipFrame("pvr.AutoSkipFrame", 0);
Option<int> RenderResolution("rend.Resolution", 480);
Option<bool> VSync("rend.vsync", true);
Option<u64> PixelBufferSize("rend.PixelBufferSize", 512 * 1024 * 1024);
Option<int64_t> PixelBufferSize("rend.PixelBufferSize", 512 * 1024 * 1024);
Option<int> AnisotropicFiltering("rend.AnisotropicFiltering", 1);
Option<int> TextureFiltering("rend.TextureFiltering", 0); // Default
Option<bool> ThreadedRendering("rend.ThreadedRendering", true);
Option<bool> DupeFrames("rend.DupeFrames", false);
Option<int> PerPixelLayers("rend.PerPixelLayers", 32);
Option<bool> NativeDepthInterpolation("rend.NativeDepthInterpolation", false);
// Misc
@@ -117,12 +121,16 @@ Option<bool> NetworkEnable("Enable", false, "network");
Option<bool> ActAsServer("ActAsServer", false, "network");
OptionString DNS("DNS", "46.101.91.123", "network");
OptionString NetworkServer("server", "", "network");
Option<int> LocalPort("LocalPort", NaomiNetwork::SERVER_PORT, "network");
Option<bool> EmulateBBA("EmulateBBA", false, "network");
Option<bool> EnableUPnP("EnableUPnP", true, "network");
Option<bool> GGPOEnable("GGPO", false, "network");
Option<int> GGPODelay("GGPODelay", 0, "network");
Option<bool> NetworkStats("Stats", true, "network");
Option<int> GGPOAnalogAxes("GGPOAnalogAxes", 0, "network");
Option<bool> GGPOChat("GGPOChat", true, "network");
Option<bool> GGPOChatTimeoutToggle("GGPOChatTimeoutToggle", true, "network");
Option<int> GGPOChatTimeout("GGPOChatTimeout", 10, "network");
#ifdef SUPPORT_DISPMANX
Option<bool> DispmanxMaintainAspect("maintain_aspect", true, "dispmanx");
+28 -3
View File
@@ -142,7 +142,11 @@ public:
else if (PerGameOption && settings.hasPerGameConfig())
{
if (value == doLoad(section, name))
{
// delete existing per-game option if any
cfgDeleteEntry(settings.gameId, section + "." + name);
return;
}
}
if (PerGameOption && settings.hasPerGameConfig())
doSave(settings.gameId, section + "." + name);
@@ -175,9 +179,16 @@ protected:
return cfgLoadBool(section, name, value);
}
template <typename U = T>
enable_if_t<std::is_same<U, int64_t>::value, T>
doLoad(const std::string& section, const std::string& name) const
{
return cfgLoadInt64(section, name, value);
}
template <typename U = T>
enable_if_t<(std::is_integral<U>::value || std::is_enum<U>::value)
&& !std::is_same<U, bool>::value, T>
&& !std::is_same<U, bool>::value && !std::is_same<U, int64_t>::value, T>
doLoad(const std::string& section, const std::string& name) const
{
return (T)cfgLoadInt(section, name, (int)value);
@@ -267,9 +278,16 @@ protected:
cfgSaveBool(section, name, value);
}
template <typename U = T>
enable_if_t<std::is_same<U, int64_t>::value>
doSave(const std::string& section, const std::string& name) const
{
cfgSaveInt64(section, name, value);
}
template <typename U = T>
enable_if_t<(std::is_integral<U>::value || std::is_enum<U>::value)
&& !std::is_same<U, bool>::value>
&& !std::is_same<U, bool>::value && !std::is_same<U, int64_t>::value>
doSave(const std::string& section, const std::string& name) const
{
cfgSaveInt(section, name, (int)value);
@@ -355,6 +373,7 @@ extern Option<bool> ForceWindowsCE;
extern Option<bool> AutoLoadState;
extern Option<bool> AutoSaveState;
extern Option<int> SavestateSlot;
extern Option<bool> ForceFreePlay;
// Sound
@@ -421,6 +440,7 @@ constexpr bool Clipping = true;
#ifndef LIBRETRO
extern Option<int> TextureUpscale;
extern Option<int> MaxFilteredTextureSize;
extern Option<int> PerPixelLayers;
#endif
extern Option<float> ExtraDepthScale;
extern Option<bool> CustomTextures;
@@ -438,11 +458,12 @@ extern Option<int> MaxThreads;
extern Option<int> AutoSkipFrame; // 0: none, 1: some, 2: more
extern Option<int> RenderResolution;
extern Option<bool> VSync;
extern Option<u64> PixelBufferSize;
extern Option<int64_t> PixelBufferSize;
extern Option<int> AnisotropicFiltering;
extern Option<int> TextureFiltering; // 0: default, 1: force nearest, 2: force linear
extern Option<bool> ThreadedRendering;
extern Option<bool> DupeFrames;
extern Option<bool> NativeDepthInterpolation;
// Misc
@@ -462,12 +483,16 @@ extern Option<bool> NetworkEnable;
extern Option<bool> ActAsServer;
extern OptionString DNS;
extern OptionString NetworkServer;
extern Option<int> LocalPort;
extern Option<bool> EmulateBBA;
extern Option<bool> EnableUPnP;
extern Option<bool> GGPOEnable;
extern Option<int> GGPODelay;
extern Option<bool> NetworkStats;
extern Option<int> GGPOAnalogAxes;
extern Option<bool> GGPOChat;
extern Option<bool> GGPOChatTimeoutToggle;
extern Option<int> GGPOChatTimeout;
#ifdef SUPPORT_DISPMANX
extern Option<bool> DispmanxMaintainAspect;
+306 -253
View File
@@ -25,285 +25,315 @@
#include "reios/reios.h"
#include "cfg/cfg.h"
#include "cfg/ini.h"
#include "emulator.h"
const WidescreenCheat CheatManager::widescreen_cheats[] =
{
{ "MK-51064", nullptr, { 0x39EFF4, 0 }, { 0x43700000 } }, // 18 wheeler (USA)
{ "MK-5106450", nullptr, { 0x39EFF4, 0 }, { 0x43700000 } }, // 18 wheeler (PAL)
{ "HDR-0080", nullptr, { 0x6625C0, 0 }, { 0x43700000 } }, // 18 wheeler (JP)
{ "T-9708N", nullptr, { 0x0AD5B0, 0x112E00, 0 }, { 0x4A2671C4, 0x401CCCCD } }, // 4 Wheel Thunder (USA)
{ "MK-5119050", nullptr, { 0x104A34, 0 }, { 0x3F52CCCD } }, // 90 Minutes - Sega Championship Football (PAL)
{ "T40209D 50", nullptr, { 0x2A8750, 0 }, { 0x3F400000 } }, // AeroWings 2 (PAL)
{ "T34101M", nullptr, { 0x24CF20, 0x24CEEC, 0 }, { 0x3FAAAAAB, 0x43F00000, 0 } }, // Animastar (JP)
{ "MK-51171", nullptr, { 0xCA20B8, 0 }, { 0x43700000 } }, // Alien Front Online (USA)
{ "T2101M", nullptr, { 0x13E8B4, 0x13E8E4, 0 }, { 0x43F00000, 0x3F400000 } }, // Berserk (JP)
{ "T13001D 18", nullptr, { 0x2DAC44, 0 }, { 0x3F400000 } }, // Blue Stinger (En, De) (PAL)
{ "xxxxxxxxxx", nullptr, { 0x2DAB84, 0 }, { 0x3F400000 } }, // Blue Stinger (Fr) (PAL)
{ "T13001D-05", nullptr, { 0x2D9C84, 0 }, { 0x3F400000 } }, // Blue Stinger (Es, It?) (PAL)
{ "T13001N", nullptr, { 0x2D9CA4, 0 }, { 0x3F400000 } }, // Blue Stinger (USA)
{ "HDR-0003", nullptr, { 0x2D6D80, 0 }, { 0x3F400000 } }, // Blue Stinger (JP)
{ "T42903M", nullptr, { 0x286E2C, 0x286E5C, 0 }, { 0x43F00000, 0x3F400000 } }, // Bomber Hehhe! (JP)
{ "MK-51065", nullptr, { 0x387B84, 0x387BB4, 0 }, { 0x43F00000, 0x3F400000 } }, // Bomberman Online (USA)
{ "T6801M", nullptr, { 0x042F3C, 0 }, { 0x4384BC09 } }, // Buggy Heat (JP)
{ "T46601D 05", nullptr, { 0xBB3D14, 0 }, { 0x440A7C9A } }, // Cannon Spike (PAL)
{ "T1215N", nullptr, { 0xBB3C74, 0 }, { 0x440A7C9A } }, // Cannon Spike (USA)
{ "T44901D 50", nullptr, { 0xB0109C, 0xB010CC, 0 }, { 0x43F00000, 0x3F400000 } }, // Carrier (PAL)
{ "T5701N", nullptr, { 0xAFD93C, 0xAFD96C, 0 }, { 0x43F00000, 0x3F400000 } }, // Carrier (USA)
{ "MK-51064", nullptr, { 0x39EFF4 }, { 0x43700000 } }, // 18 wheeler (USA)
{ "MK-5106450", nullptr, { 0x39EFF4 }, { 0x43700000 } }, // 18 wheeler (PAL)
{ "HDR-0080", nullptr, { 0x6625C0 }, { 0x43700000 } }, // 18 wheeler (JP)
{ "T-9708N", nullptr, { 0x0AD5B0, 0x112E00 }, { 0x4A2671C4, 0x401CCCCD } }, // 4 Wheel Thunder (USA)
{ "MK-5119050", nullptr, { 0x104A34 }, { 0x3F52CCCD } }, // 90 Minutes - Sega Championship Football (PAL)
{ "T40209D 50", nullptr, { 0x2A8750 }, { 0x3F400000 } }, // AeroWings 2 (PAL)
{ "T34101M", nullptr, { 0x24CF20, 0x24CEEC }, { 0x3FAAAAAB, 0x43F00000 } }, // Animastar (JP)
{ "MK-51171", nullptr, { 0xCA20B8 }, { 0x43700000 } }, // Alien Front Online (USA)
{ "T2101M", nullptr, { 0x13E8B4, 0x13E8E4 }, { 0x43F00000, 0x3F400000 } }, // Berserk (JP)
{ "T13001D 18", nullptr, { 0x2DAC44 }, { 0x3F400000 } }, // Blue Stinger (En, De) (PAL)
{ "xxxxxxxxxx", nullptr, { 0x2DAB84 }, { 0x3F400000 } }, // Blue Stinger (Fr) (PAL)
{ "T13001D-05", nullptr, { 0x2D9C84 }, { 0x3F400000 } }, // Blue Stinger (Es, It?) (PAL)
{ "T13001N", nullptr, { 0x2D9CA4 }, { 0x3F400000 } }, // Blue Stinger (USA)
{ "HDR-0003", nullptr, { 0x2D6D80 }, { 0x3F400000 } }, // Blue Stinger (JP)
{ "T42903M", nullptr, { 0x286E2C, 0x286E5C }, { 0x43F00000, 0x3F400000 } }, // Bomber Hehhe! (JP)
{ "MK-51065", nullptr, { 0x387B84, 0x387BB4 }, { 0x43F00000, 0x3F400000 } }, // Bomberman Online (USA)
{ "T6801M", nullptr, { 0x042F3C }, { 0x4384BC09 } }, // Buggy Heat (JP)
{ "T46601D 05", nullptr, { 0xBB3D14 }, { 0x440A7C9A } }, // Cannon Spike (PAL)
{ "T1215N", nullptr, { 0xBB3C74 }, { 0x440A7C9A } }, // Cannon Spike (USA)
{ "T44901D 50", nullptr, { 0xB0109C, 0xB010CC }, { 0x43F00000, 0x3F400000 } }, // Carrier (PAL)
{ "T5701N", nullptr, { 0xAFD93C, 0xAFD96C }, { 0x43F00000, 0x3F400000 } }, // Carrier (USA)
// Capcom vs. SNK Pro (JP)
// You can see the end of the backgrounds on each side. The HUD is shifted to the right.
// Code 2 sets HUD and movements of the characters to a 4:3 zone
{ "T1247M", nullptr, { 0x1E8238, 0x3D3658, 0x3D3628, 0 }, { 0x43F00000, 0x43D20000, 0x43700000 } },
{ "T1247M", nullptr, { 0x1E8238, 0x3D3658, 0x3D3628 }, { 0x43F00000, 0x43D20000, 0x43700000 } },
// Capcom vs. SNK 2 (JP)
// You can see the end of the backgrounds on each side.
{ "T1249M", nullptr, { 0x39BFD8, 0x34E9E8, 0x34EFBC, 0 }, { 0x43700000, 0x3F400000, 0x3F400000 } },
{ "T44902D 50", nullptr, { 0x1DBFF8, 0 }, { 0x43700000 } }, // Charge ‘n Blast (PAL)
{ "T4402M", nullptr, { 0x1DA9E0, 0 }, { 0x43700000 } }, // Charge ‘n Blast (JP)
{ "MK-5104950", nullptr, { 0x2D2D40, 0x2D2D70, 0 }, { 0x3F400000, 0xC2700000 } }, // ChuChu Rocket! (PAL)
{ "T44903D 50", nullptr, { 0x315300, 0x315334, 0 }, { 0x43F00000, 0x3FAAAAAB } }, // Coaster Works (PAL)
{ "T1249M", nullptr, { 0x39BFD8, 0x34E9E8, 0x34EFBC }, { 0x43700000, 0x3F400000, 0x3F400000 } },
{ "T44902D 50", nullptr, { 0x1DBFF8 }, { 0x43700000 } }, // Charge ‘n Blast (PAL)
{ "T4402M", nullptr, { 0x1DA9E0 }, { 0x43700000 } }, // Charge ‘n Blast (JP)
{ "MK-5104950", nullptr, { 0x2D2D40, 0x2D2D70 }, { 0x3F400000, 0xC2700000 } }, // ChuChu Rocket! (PAL)
{ "T44903D 50", nullptr, { 0x315300, 0x315334 }, { 0x43F00000, 0x3FAAAAAB } }, // Coaster Works (PAL)
// Confidential Mission (PAL) 022F0D58 43700000 - Only works on real Dreamcast
{ "T36901M", nullptr, { 0x1C8A98, 0 }, { 0x3F400000 } }, // Cool Boarders (JP)
{ "T3106M", nullptr, { 0x60B59C, 0 }, { 0x3F400000 } }, // Cool Cool Toon (JP)
{ "HDR-0176", nullptr, { 0x240FAC, 0 }, { 0x3F400000 } }, // Cosmic Smash (JP)
{ "MK-51035", " U ", { 0x2B08B0, 0 }, { 0x43700000 } }, // Crazy Taxi (USA)
{ "MK-51035", " E ", { 0x2B3410, 0 }, { 0x43700000 } }, // Crazy Taxi (PAL)
{ "MK-5113650", nullptr, { 0x2BFB70, 0 }, { 0x43700000 } }, // Crazy Taxi 2 (PAL)
{ "MK-51136", nullptr, { 0x2BDDD0, 0 }, { 0x43700000 } }, // Crazy Taxi 2 (USA)
// { "HDR-0159", nullptr, { 0x2FBBD0, 0 }, { 0x43700000 } }, // Crazy Taxi 2 (JP) not working
{ "T13004N", nullptr, { 0x016D94, 0 }, { 0x44234E73 } }, // Cyber Troopers - Virtual On - Oratorio Tangram (USA)
{ "T36901M", nullptr, { 0x1C8A98 }, { 0x3F400000 } }, // Cool Boarders (JP)
{ "T3106M", nullptr, { 0x60B59C }, { 0x3F400000 } }, // Cool Cool Toon (JP)
{ "HDR-0176", nullptr, { 0x240FAC }, { 0x3F400000 } }, // Cosmic Smash (JP)
{ "MK-51035", " U ", { 0x2B08B0 }, { 0x43700000 } }, // Crazy Taxi (USA)
{ "MK-51035", " E ", { 0x2B3410 }, { 0x43700000 } }, // Crazy Taxi (PAL)
{ "MK-5113650", nullptr, { 0x2BFB70 }, { 0x43700000 } }, // Crazy Taxi 2 (PAL)
{ "MK-51136", nullptr, { 0x2BDDD0 }, { 0x43700000 } }, // Crazy Taxi 2 (USA)
// { "HDR-0159", nullptr, { 0x2FBBD0 }, { 0x43700000 } }, // Crazy Taxi 2 (JP) not working
{ "T13004N", nullptr, { 0x016D94 }, { 0x44234E73 } }, // Cyber Troopers - Virtual On - Oratorio Tangram (USA)
// D2 (USA)
{ "MK-51036", nullptr, { 0x4B5CF4, 0x4B5CC4, 0x3E92A0, 0x3E92A8, 0x3E92C0, 0x3E92C8 },
{ 0x3F400000, 0x43F00000, 0, 0, 0, 0 } },
// D2 (JP)
{ "T30006M", nullptr, { 0x4CF42C, 0x4CF45C, 0x3E1A36, 0x3E1A34, 0x3E1A3C, 0x3E1A54, 0x3E1A5C, 0 },
{ "T30006M", nullptr, { 0x4CF42C, 0x4CF45C, 0x3E1A36, 0x3E1A34, 0x3E1A3C, 0x3E1A54, 0x3E1A5C },
{ 0x43F00000, 0x3F400000, 0x08010000, 0, 0, 0, 0 } },
{ "MK-5103750", nullptr, { 0x1FE270, 0 }, { 0x43700000 } }, // Daytona USA (PAL)
{ "MK-51037", nullptr, { 0x1FC6D0, 0 }, { 0x43700000 } }, // Daytona USA (USA)
{ "T9501N-50", nullptr, { 0x9821D4, 0 }, { 0x3F400000 } }, // Deadly Skies (PAL)
{ "T8116D 50", nullptr, { 0x2E5530, 0 }, { 0x43700000 } }, // Dead or Alive 2 (PAL)
{ "T3601N", nullptr, { 0x2F0670, 0 }, { 0x43700000 } }, // Dead or Alive 2 (USA)
{ "T3602M", nullptr, { 0x2FF798, 0 }, { 0x43700000 } }, // Dead or Alive 2 (JP)
{ "T3601M", nullptr, { 0x2FBBD0, 0x1E6658, 0 }, { 0x43700000, 0x4414C000 } }, // Dead or Alive 2: Limited Edition (JP) (code 1 fixes HUD)
{ "T2401N", nullptr, { 0x8BD5B4, 0x8BD5E4, 0 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson OX (USA)
{ "T23201M", nullptr, { 0x819F44, 0x819F74, 0 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson 2 (JP)
{ "T17714D50", nullptr, { 0x0D2ED0, 0x0D2ED4, 0 }, { 0x3FAAAAAB, 0x3F400000 } }, // Donald Duck: Quack Attack (PAL) (Code 1 corrects the HUD)
{ "T12503D-50", nullptr, { 0x49CB24, 0 }, { 0x3F0CCCCD } }, // Dragons Blood (PAL)
{ "T17716D 50", nullptr, { 0xF97F40, 0x08DCF8, 0 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (PAL)
{ "T17720N", nullptr, { 0xF97F40, 0x08DCF4, 0 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (USA) (Code 1 removes black bars)
{ "MK-5101350", nullptr, { 0x4FCBC0, 0 }, { 0x43700000 } }, // Dynamite Cop (PAL)
{ "MK-51013", nullptr, { 0x4FCBC0, 0 }, { 0x43700000 } }, // Dynamite Cop (USA)
{ "MK-5103750", nullptr, { 0x1FE270 }, { 0x43700000 } }, // Daytona USA (PAL)
{ "MK-51037", nullptr, { 0x1FC6D0 }, { 0x43700000 } }, // Daytona USA (USA)
{ "T9501N-50", nullptr, { 0x9821D4 }, { 0x3F400000 } }, // Deadly Skies (PAL)
{ "T8116D 50", nullptr, { 0x2E5530 }, { 0x43700000 } }, // Dead or Alive 2 (PAL)
{ "T3601N", nullptr, { 0x2F0670 }, { 0x43700000 } }, // Dead or Alive 2 (USA)
{ "T3602M", nullptr, { 0x2FF798 }, { 0x43700000 } }, // Dead or Alive 2 (JP)
{ "T3601M", nullptr, { 0x2FBBD0 }, { 0x43700000 } }, // Dead or Alive 2: Limited Edition (JP)
{ "T2401N", nullptr, { 0x8BD5B4, 0x8BD5E4 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson OX (USA)
{ "T23201M", nullptr, { 0x819F44, 0x819F74 }, { 0x43F00000, 0x3F400000 } }, // Death Crimson 2 (JP)
{ "T17714D50", nullptr, { 0x0D2ED0, 0x0D2ED4 }, { 0x3FAAAAAB, 0x3F400000 } }, // Donald Duck: Quack Attack (PAL) (Code 1 corrects the HUD)
{ "T12503D-50", nullptr, { 0x49CB24 }, { 0x3F0CCCCD } }, // Dragons Blood (PAL)
{ "T17716D 50", nullptr, { 0xF97F40, 0x08DCF8 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (PAL)
{ "T17720N", nullptr, { 0xF97F40, 0x08DCF4 }, { 0x00000168, 0 } }, // Dragonriders: Chronicles of Pern (USA) (Code 1 removes black bars)
{ "MK-5101350", nullptr, { 0x4FCBC0 }, { 0x43700000 } }, // Dynamite Cop (PAL)
{ "MK-51013", nullptr, { 0x4FCBC0 }, { 0x43700000 } }, // Dynamite Cop (USA)
{ "HDR-0020", nullptr, { 0x4FA848 }, { 0x43700000 } }, // Dynamite Deka 2 (JP)
// Draconus: Cult of the Wyrm (USA)
// Code 1-2 increases drawing distance
{ "T40203N", nullptr, { 0x49D7F4, 0x49D8CC, 0x49D6F8, 0 }, { 0x3F07C3BB, 0x447A0000, 0x3FAAAAAB } },
{ "T40203N", nullptr, { 0x49D7F4, 0x49D8CC, 0x49D6F8 }, { 0x3F07C3BB, 0x447A0000, 0x3FAAAAAB } },
// Ecco the Dolphin: Defender of the Future (PAL)
{ "MK-5103350", nullptr, { 0x275418, 0x040E68, 0x040D1C, 0 }, { 0x49D9A5DA, 0x3F100000, 0x3F100000 } },
{ "T17705D 05", nullptr, { 0x304870, 0 }, { 0x3F400000 } }, // Evolution - The World of Sacred Device (PAL)
{ "T45005D 50", nullptr, { 0x36CE5C, 0x36CE8C, 0 }, { 0x43F00000, 0x3F400000 } }, // Evolution 2 - Far Off Promise (PAL)
{ "T1711N", nullptr, { 0x36C76C, 0x36C73C, 0 }, { 0x3F400000, 0x43F00000 } }, // Evolution 2 - Far Off Promise (USA)
{ "T8118D 50", nullptr, { 0x2C6B7C, 0 }, { 0x00004000 } }, // Ferrari F355 Challenge (PAL) vga mode only
{ "HDR-0100", nullptr, { 0x3235D4, 0 }, { 0x00004000 } }, // Ferrari F355 Challenge (JP) vga mode only
{ "MK-5115450", nullptr, { 0x3D3B10, 0 }, { 0x43700000 } }, // Fighting Vipers 2 (PAL)
{ "HDR-0133", nullptr, { 0x3D3AF0, 0 }, { 0x43700000 } }, // Fighting Vipers 2 (JP)
{ "MK-51114", nullptr, { 0x132DD8, 0xA26CA8, 0xA26738, 0xA275B8, 0xA26AD8, 0xA26908, 0 },
{ "MK-5103350", nullptr, { 0x275418, 0x040E68, 0x040D1C }, { 0x49D9A5DA, 0x3F100000, 0x3F100000 } },
{ "T17705D 05", nullptr, { 0x304870 }, { 0x3F400000 } }, // Evolution - The World of Sacred Device (PAL)
{ "T45005D 50", nullptr, { 0x36CE5C, 0x36CE8C }, { 0x43F00000, 0x3F400000 } }, // Evolution 2 - Far Off Promise (PAL)
{ "T1711N", nullptr, { 0x36C76C, 0x36C73C }, { 0x3F400000, 0x43F00000 } }, // Evolution 2 - Far Off Promise (USA)
{ "T8118D 50", nullptr, { 0x2C6B7C }, { 0x00004000 } }, // Ferrari F355 Challenge (PAL) vga mode only
{ "HDR-0100", nullptr, { 0x3235D4 }, { 0x00004000 } }, // Ferrari F355 Challenge (JP) vga mode only
{ "MK-5115450", nullptr, { 0x3D3B10 }, { 0x43700000 } }, // Fighting Vipers 2 (PAL)
{ "HDR-0133", nullptr, { 0x3D3AF0 }, { 0x43700000 } }, // Fighting Vipers 2 (JP)
{ "MK-51114", nullptr, { 0x132DD8, 0xA26CA8, 0xA26738, 0xA275B8, 0xA26AD8, 0xA26908 },
{ 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000 } }, // Floigan Bros. Ep. 1 (PAL)
{ "T34201M", nullptr, { 0x586290, 0x586260, 0 }, { 0x3F400000, 0x43F00000 } }, // Frame Gride (JP)
{ "T-8113D-50", nullptr, { 0x55A354, 0 }, { 0x3FAAAAAB } }, // Fur Fighters (PAL)
{ "T-8107N", nullptr, { 0x55A374, 0 }, { 0x3FAAAAAB } }, // Fur Fighters (USA)
{ "T9707D 50", nullptr, { 0x2E7CD0, 0x2E7D04, 0x2E7D10, 0x2E7D0C, 0 },
{ "T34201M", nullptr, { 0x586290, 0x586260 }, { 0x3F400000, 0x43F00000 } }, // Frame Gride (JP)
{ "T-8113D-50", nullptr, { 0x55A354 }, { 0x3FAAAAAB } }, // Fur Fighters (PAL)
{ "T-8107N", nullptr, { 0x55A374 }, { 0x3FAAAAAB } }, // Fur Fighters (USA)
{ "T9707D 50", nullptr, { 0x2E7CD0, 0x2E7D04, 0x2E7D10, 0x2E7D0C },
{ 0x43BEAE39, 0x3DCCCCCD , 0x44A00000, 0xC4200000 } }, // Gauntlet Legends (PAL)
{ "HDR-0004", nullptr, { 0x364A64, 0 }, { 0x43BA0000 } }, // Godzilla Generations (JP)
{ "HDR-0047", nullptr, { 0x7C3F24, 0x7C3F54, 0 }, { 0x43F00000, 0x3F400000 } }, // Godzilla Generations Maximum Impact (JP)
{ "T41501M", nullptr, { 0x282604, 0x282634, 0 }, { 0x43F00000, 0x3F400000 } }, // Golem no Maigo (aka The Lost Golem) (JP)
{ "T1219M", nullptr, { 0xBC3C94, 0 }, { 0x440A7C9A } }, // Gun Spike (JP)
{ "T13301N", nullptr, { 0x88E780, 0 }, { 0x3F400000 } }, // Gundam Side Story (USA)
// { "T11001N", nullptr, { 0xC3D6BC, 0xD204A8, 0xD32FC8, 0xC7CF84, 0xD20548, 0 },
{ "HDR-0004", nullptr, { 0x364A64 }, { 0x43BA0000 } }, // Godzilla Generations (JP)
{ "HDR-0047", nullptr, { 0x7C3F24, 0x7C3F54 }, { 0x43F00000, 0x3F400000 } }, // Godzilla Generations Maximum Impact (JP)
{ "T41501M", nullptr, { 0x282604, 0x282634 }, { 0x43F00000, 0x3F400000 } }, // Golem no Maigo (aka The Lost Golem) (JP)
{ "T1219M", nullptr, { 0xBC3C94 }, { 0x440A7C9A } }, // Gun Spike (JP)
{ "T13301N", nullptr, { 0x88E780 }, { 0x3F400000 } }, // Gundam Side Story (USA)
// { "T11001N", nullptr, { 0xC3D6BC, 0xD204A8, 0xD32FC8, 0xC7CF84, 0xD20548 },
// { 0x00363031, 0x00000356, 0x00000280, 0x00000280, 0x00000280 } }, // Half-Life. Not working
{ "MK-5104150", nullptr, { 0x23FCC4, 0 }, { 0x44558000 } }, // Headhunter (PAL)
{ "MK-5100250", nullptr, { 0x4C6708, 0 }, { 0x43700000 } }, // House of the Dead 2, The (PAL)
{ "MK-51002", nullptr, { 0x4C6088, 0 }, { 0x43700000 } }, // House of the Dead 2, The (USA)
{ "T38706M", nullptr, { 0xC0CFA0, 0 }, { 0x3F400000 } }, // Ikaruga (JP)
{ "T46001N", nullptr, { 0x1C8A98, 0 }, { 0x3F400000 } }, // Illbleed (USA)
{ "T44904D 50", nullptr, { 0x18C15C, 0x18C18C, 0 }, { 0x43F00000, 0x3F400000 } }, // Iron Aces (PAL)
{ "MK-51058", nullptr, { 0x32E0FC, 0x32E12C, 0 }, { 0x43F00000, 0x3F400000 } }, // Jet Grind Radio (USA)
{ "MK-5105850", nullptr, { 0x32F9EC, 0x32F9BC, 0 }, { 0x3F400000, 0x43F00000 } }, // Jet Set Radio (PAL)
{ "HDR-0078", nullptr, { 0x327A8C, 0x327A5C, 0 }, { 0x3F400000, 0x43F00000 } }, // Jet Set Radio (De La) (JP)
{ "T22902D 50", nullptr, { 0x278508, 0 }, { 0x43700000 } }, // Kao The Kangaroo (PAL)
{ "T22903N", nullptr, { 0x2780A8, 0 }, { 0x43700000 } }, // Kao The Kangaroo (USA)
{ "T47803M", nullptr, { 0x0FDFAC, 0 }, { 0x3F400000 } }, // Karous (JP)
// { "T41901N", nullptr, { 0x53F580, 0xEFB748, 0xEFB750, 0 }, { 0xC4200000, 0x43A00000, 0x43200000 } }, // KISS Psycho Circus – The Nightmare Child (USA)
{ "T2501M", nullptr, { 0x24A878, 0x24A8A8, 0 }, { 0x43F00000, 0x3F400000 } }, // Langrisser Millenium (JP)
{ "T15111D 50", nullptr, { 0x29B90C, 0 }, { 0x3F400000 } }, // Le Mans 24 Hours (PAL)
{ "T15116N", nullptr, { 0x2198EC, 0 }, { 0x3F400000 } }, // Looney Tunes: Space Race (USA)
{ "MK-5105050", nullptr, { 0x33818C, 0 }, { 0x3FA66666 } }, // Maken X (PAL)
{ "MK-51050", nullptr, { 0x30CB4C, 0 }, { 0x3F400000 } }, // Maken X (USA)
{ "T1212N", nullptr, { 0x2D6B18, 0x268390, 0x268ED8, 0x268934, 0x26947C, 0x269A20, 0x269FC4, 0 },
{ "MK-5104150", nullptr, { 0x23FCC4 }, { 0x44558000 } }, // Headhunter (PAL)
{ "MK-5100250", nullptr, { 0x4C6708 }, { 0x43700000 } }, // House of the Dead 2, The (PAL)
{ "MK-51002", nullptr, { 0x4C6088 }, { 0x43700000 } }, // House of the Dead 2, The (USA)
{ "T38706M", nullptr, { 0xC0CFA0 }, { 0x3F400000 } }, // Ikaruga (JP)
{ "T46001N", nullptr, { 0x1C8A98 }, { 0x3F400000 } }, // Illbleed (USA)
{ "T44904D 50", nullptr, { 0x18C15C, 0x18C18C }, { 0x43F00000, 0x3F400000 } }, // Iron Aces (PAL)
{ "MK-51058", nullptr, { 0x32E0FC, 0x32E12C }, { 0x43F00000, 0x3F400000 } }, // Jet Grind Radio (USA)
{ "MK-5105850", nullptr, { 0x32F9EC, 0x32F9BC }, { 0x3F400000, 0x43F00000 } }, // Jet Set Radio (PAL)
{ "HDR-0078", nullptr, { 0x327A8C, 0x327A5C }, { 0x3F400000, 0x43F00000 } }, // Jet Set Radio (De La) (JP)
{ "T22902D 50", nullptr, { 0x278508 }, { 0x43700000 } }, // Kao The Kangaroo (PAL)
{ "T22903N", nullptr, { 0x2780A8 }, { 0x43700000 } }, // Kao The Kangaroo (USA)
{ "T47803M", nullptr, { 0x0FDFAC }, { 0x3F400000 } }, // Karous (JP)
// { "T41901N", nullptr, { 0x53F580, 0xEFB748, 0xEFB750 }, { 0xC4200000, 0x43A00000, 0x43200000 } }, // KISS Psycho Circus – The Nightmare Child (USA)
{ "T2501M", nullptr, { 0x24A878, 0x24A8A8 }, { 0x43F00000, 0x3F400000 } }, // Langrisser Millenium (JP)
{ "T15111D 50", nullptr, { 0x29B90C }, { 0x3F400000 } }, // Le Mans 24 Hours (PAL)
{ "T15116N", nullptr, { 0x2198EC }, { 0x3F400000 } }, // Looney Tunes: Space Race (USA)
{ "MK-5105050", nullptr, { 0x33818C }, { 0x3FA66666 } }, // Maken X (PAL)
{ "MK-51050", nullptr, { 0x30CB4C }, { 0x3F400000 } }, // Maken X (USA)
{ "T1212N", nullptr, { 0x2D6B18, 0x268390, 0x268ED8, 0x268934, 0x26947C, 0x269A20, 0x269FC4 },
{ 0x43700000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000 } }, // Marvel vs. Capcom 2 (USA)
{ "T1215M", nullptr, { 0x2FE2C0, 0x28FB38, 0x290680, 0x2900DC, 0x290C24, 0x2911C8, 0x29176C, 0 },
{ "T1215M", nullptr, { 0x2FE2C0, 0x28FB38, 0x290680, 0x2900DC, 0x290C24, 0x2911C8, 0x29176C },
{ 0x43700000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000, 0x3F400000 } }, // Marvel vs. Capcom 2 (JP)
{ "T41402N", nullptr, { 0x551B80, 0 }, { 0x3F400000 } }, // Max Steel - Covert Missions (USA)
{ "MK-5102250", "V1.001", { 0x107FDC, 0x11253C, 0 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.001) (PAL)
{ "MK-5102250", "V1.009", { 0x106B5C, 0x1111F4, 0 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.009) (PAL)
{ "MK-51012", nullptr, { 0x10A01C, 0x1146FC, 0 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (USA)
{ "T0000M", nullptr, { 0x1CAEAC, 0x1CAEDC, 0 }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters
{ "T1221M", nullptr, { 0x426B74, 0 }, { 0x43F00000 } }, // Moero! Justice Gauken (JP)
{ "T9701D", nullptr, { 0x31290C, 0 }, { 0x3F400000 } }, // Mortal Kombat Gold (PAL)
{ "T-9701N", nullptr, { 0x337B8C, 0 }, { 0x3FA66666 } }, // Mortal Kombat Gold (USA)
{ "T7020D", nullptr, { 0x1A5D40, 0x1A5D18, 0x1A5D38, 0x1A5D34, 0x1A5D30, 0x1A5D3C, 0x1A5D0C, 0x1A5D08, 0x1ACB78, 0 },
{ "T41402N", nullptr, { 0x551B80 }, { 0x3F400000 } }, // Max Steel - Covert Missions (USA)
{ "MK-5102250", "V1.001", { 0x107FDC, 0x11253C }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.001) (PAL)
{ "MK-5102250", "V1.009", { 0x106B5C, 0x1111F4 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.009) (PAL)
{ "MK-51012", nullptr, { 0x10A01C, 0x1146FC }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (USA)
{ "T0000M", nullptr, { 0x1CAEAC, 0x1CAEDC }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters
{ "T1221M", nullptr, { 0x426B74 }, { 0x43F00000 } }, // Moero! Justice Gauken (JP)
{ "T9701D", nullptr, { 0x31290C }, { 0x3F400000 } }, // Mortal Kombat Gold (PAL)
{ "T-9701N", nullptr, { 0x337B8C }, { 0x3FA66666 } }, // Mortal Kombat Gold (USA)
{ "T7020D", nullptr, { 0x1A5D40, 0x1A5D18, 0x1A5D38, 0x1A5D34, 0x1A5D30, 0x1A5D3C, 0x1A5D0C, 0x1A5D08, 0x1ACB78 },
{ 0x3F59999A, 0x44084000, 0x3FB1EB85, 0x3FAAAAAB, 0x3F800000, 0x3FA66666, 0xC31B0000, 0x42700000, 0x44160000 } }, // Mr Driller (PAL)
{ "T7604M", nullptr, { 0x43BDA4, 0x43BDD8, 0x4319E8, 0x431A08, 0x431A28, 0x431A48, 0 },
{ "T7604M", nullptr, { 0x43BDA4, 0x43BDD8, 0x4319E8, 0x431A08, 0x431A28, 0x431A48 },
{ 0x43700000, 0x3F9AF5C2, 0x42200000, 0x42200000, 0x438C0000, 0x438C0000 } }, // Nanatsu no Hikan - Senritsu no Bishou (JP)
{ "HDR-0079", nullptr, { 0x353744, 0x353774, 0x353778, 0 },
{ "HDR-0079", nullptr, { 0x353744, 0x353774, 0x353778 },
{ 0x43F00000, 0x3F400000, 0x3F800000 } }, // Napple Tale: Arsia in Daydream (JP)
//crash { "MK-51178", nullptr, { 0x23AF00, 0x23B160, 0x144D40, 0x2105B4, 0x705B40, 0 },
//crash { "MK-51178", nullptr, { 0x23AF00, 0x23B160, 0x144D40, 0x2105B4, 0x705B40 },
// { 0xBFAAAAAB, 0xBFAAAAAB, 0xBFAAAAAB, 0xBFAAAAAB, 0x44558000 } }, // NBA 2K2
{ "T9504M", nullptr, { 0xCDE848, 0xCDE844, 0 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (USA)
{ "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4, 0 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
{ "MK-5110250", nullptr, { 0x87B5A4, 0 }, { 0x43700000 } }, // Outtrigger (PAL)
{ "HDR-0118", nullptr, { 0x83E284, 0 }, { 0x43700000 } }, // Outtrigger (JP)
{ "T15103D 50", nullptr, { 0x1EEE78, 0 }, { 0x3F400000 } }, // PenPen (PAL)
{ "T17001M", nullptr, { 0x1C3828, 0 }, { 0x3F400000 } }, // PenPen TriIcelon (JP)
{ "MK-5110050", nullptr, { 0x548E04, 0x0923C0, 0 }, { 0x43E80000, 0x3F966666 } }, // Phantasy Star Online (PAL) TODO
{ "MK-51100", nullptr, { 0x548E84, 0x0925A4, 0 }, { 0x43D20000, 0x3FA66666 } }, // Phantasy Star Online (USA) TODO
{ "HDR-0129", nullptr, { 0x57E344, 0x091794, 0 }, { 0x43D20000, 0x3FA66666 } }, // Phantasy Star Online (JP) TODO
{ "MK-5119350", nullptr, { 0x57552C, 0x0A2DD4, 0 }, { 0x43F00000, 0x3F911111 } }, // Phantasy Star Online Ver. 2 (PAL) TODO
{ "MK-51193", nullptr, { 0x0A3138, 0x58C8CC, 0 }, { 0x3F911111, 0x43F00000 } }, // Phantasy Star Online Ver. 2 (USA) TODO
{ "T1207N", nullptr, { 0x7D463C, 0 }, { 0x3F400000 } }, // Plasma Sword - Nightmare of Bilstein (USA)
{ "T36801D 50", nullptr, { 0x7FD3C8, 0 }, { 0x43700000 } }, // Power Stone (PAL)
{ "T1201N", nullptr, { 0x7FCEE8, 0 }, { 0x43700000 } }, // Power Stone (USA)
{ "T36812D 50", nullptr, { 0x868BA8, 0 }, { 0x43700000 } }, // Power Stone 2 (PAL)
{ "T1211N", nullptr, { 0x8689A8, 0 }, { 0x43700000 } }, // Power Stone 2 (USA)
{ "T1218M", nullptr, { 0x849AA0, 0 }, { 0x43700000 } }, // Power Stone 2 (JP)
{ "T7022D 50", nullptr, { 0x33414C, 0 }, { 0x43F00000 } }, // Project Justice (PAL)
{ "T1219N", nullptr, { 0x33374C, 0 }, { 0x43F00000 } }, // Project Justice (USA)
{ "MK-51162", nullptr, { 0x204308, 0 }, { 0x3FE38E39 } }, // Propeller Arena
{ "T-8106D-50", nullptr, { 0x7DA39C, 0 }, { 0x3F400000 } }, // Psychic Force 2012 (PAL)
{ "T9901M", nullptr, { 0x1AD848, 0 }, { 0x3F400000 } }, // Rainbow Cotton (JP)
{ "T9711D 50", nullptr, { 0x1574D8, 0 }, { 0x43700000 } }, // Ready 2 Rumble Boxing Round 2 (PAL)
{ "T7012D 05", nullptr, { 0x4FF93C, 0x4FF96C, 0 }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (En) (PAL)
{ "xxxxxxxxxx", nullptr, { 0x4FF25C, 0x4FF28C, 0 }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (De) (PAL)
{ "T7012D 09", nullptr, { 0x50499C, 0x5049CC, 0 }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (Fr) (PAL)
{ "MK-5102151", nullptr, { 0x3511A0, 0 }, { 0x3FC58577 } }, // Red Dog (PAL)
{ "HDR-0074", nullptr, { 0x1FF60C, 0x1FF610, 0x1FF5DC, 0 }, { 0x3F400000, 0x3F800000, 0x43DC0000 } }, //Rent a Hero n°1
{ "T9504M", nullptr, { 0xCDE848, 0xCDE844 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (USA)
{ "T-9502D-50", nullptr, { 0xBDE9B0, 0xBDE9C4 }, { 0x3F400000, 0x3FA00000 } }, // Nightmare Creatures II (PAL)
{ "MK-5110250", nullptr, { 0x87B5A4 }, { 0x43700000 } }, // Outtrigger (PAL)
{ "HDR-0118", nullptr, { 0x83E284 }, { 0x43700000 } }, // Outtrigger (JP)
{ "T15103D 50", nullptr, { 0x1EEE78 }, { 0x3F400000 } }, // PenPen (PAL)
{ "T17001M", nullptr, { 0x1C3828 }, { 0x3F400000 } }, // PenPen TriIcelon (JP)
{ "MK-5110050", nullptr, { 0x548E04, 0x0923C0 }, { 0x43E80000, 0x3F966666 } }, // Phantasy Star Online (PAL) TODO
{ "MK-51100", nullptr, { 0x548E84, 0x0925A4 }, { 0x43D20000, 0x3FA66666 } }, // Phantasy Star Online (USA) TODO
{ "HDR-0129", nullptr, { 0x57E344, 0x091794 }, { 0x43D20000, 0x3FA66666 } }, // Phantasy Star Online (JP) TODO
{ "MK-5119350", nullptr, { 0x57552C, 0x0A2DD4 }, { 0x43F00000, 0x3F911111 } }, // Phantasy Star Online Ver. 2 (PAL) TODO
{ "MK-51193", nullptr, { 0x0A3138, 0x58C8CC }, { 0x3F911111, 0x43F00000 } }, // Phantasy Star Online Ver. 2 (USA) TODO
{ "T1207N", nullptr, { 0x7D463C }, { 0x3F400000 } }, // Plasma Sword - Nightmare of Bilstein (USA)
{ "T36801D 50", nullptr, { 0x7FD3C8 }, { 0x43700000 } }, // Power Stone (PAL)
{ "T1201N", nullptr, { 0x7FCEE8 }, { 0x43700000 } }, // Power Stone (USA)
{ "T36812D 50", nullptr, { 0x868BA8 }, { 0x43700000 } }, // Power Stone 2 (PAL)
{ "T1211N", nullptr, { 0x8689A8 }, { 0x43700000 } }, // Power Stone 2 (USA)
{ "T1218M", nullptr, { 0x849AA0 }, { 0x43700000 } }, // Power Stone 2 (JP)
{ "T7022D 50", nullptr, { 0x33414C }, { 0x43F00000 } }, // Project Justice (PAL)
{ "T1219N", nullptr, { 0x33374C }, { 0x43F00000 } }, // Project Justice (USA)
{ "MK-51162", nullptr, { 0x204308 }, { 0x3FE38E39 } }, // Propeller Arena
{ "T-8106D-50", nullptr, { 0x7DA39C }, { 0x3F400000 } }, // Psychic Force 2012 (PAL)
{ "T9901M", nullptr, { 0x1AD848 }, { 0x3F400000 } }, // Rainbow Cotton (JP)
{ "T9711D 50", nullptr, { 0x1574D8 }, { 0x43700000 } }, // Ready 2 Rumble Boxing Round 2 (PAL)
{ "T7012D 05", nullptr, { 0x4FF93C, 0x4FF96C }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (En) (PAL)
{ "xxxxxxxxxx", nullptr, { 0x4FF25C, 0x4FF28C }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (De) (PAL)
{ "T7012D 09", nullptr, { 0x50499C, 0x5049CC }, { 0x43F00000, 0x3F400000 } }, // Record of Lodoss War (Fr) (PAL)
{ "MK-5102151", nullptr, { 0x3511A0 }, { 0x3FC58577 } }, // Red Dog (PAL)
{ "HDR-0074", nullptr, { 0x1FF60C, 0x1FF610, 0x1FF5DC }, { 0x3F400000, 0x3F800000, 0x43DC0000 } }, //Rent a Hero n°1
// Resident Evil: Code Veronica (De) (PAL)
// Code 1-4 removes the black bars on top and bottom in FMV
{ "xxxxxxxxxx", nullptr, { 0x32A380, 0x383E18, 0x383E38, 0x383E58, 0x383E78, 0 },
{ "xxxxxxxxxx", nullptr, { 0x32A380, 0x383E18, 0x383E38, 0x383E58, 0x383E78 },
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
// Resident Evil: Code Veronica (Fr) (PAL)
// Code 1-4 removes the black bars on top and bottom in FMV
{ "T36806D 09", nullptr, { 0x32A380, 0x383E18, 0x383E38, 0x383E58, 0x383E78, 0 },
{ "T36806D 09", nullptr, { 0x32A380, 0x383E18, 0x383E38, 0x383E58, 0x383E78 },
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
// Resident Evil: Code Veronica (Sp) (PAL)
{ "xxxxxxxxxx", nullptr, { 0x32A3A0, /* 0x383E18, 0x383E38, 0x383E58, 0x383E78, */ 0 },
{ "xxxxxxxxxx", nullptr, { 0x32A3A0 /*, 0x383E18, 0x383E38, 0x383E58, 0x383E78 */ },
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
// Resident Evil: Code Veronica (USA)
// Code 1-4 removes the black bars on top and bottom in FMV
{ "T1204N", nullptr, { 0x329E40, 0x3838D8, 0x3838F8, 0x383918, 0x383938, 0 },
{ "T1204N", "RESIDENT EVIL CODE VERONICA ",
{ 0x329E40, 0x3838D8, 0x3838F8, 0x383918, 0x383938 },
{ 0x3F400000, 0x43F00000, 0, 0x43F00000, 0 } },
{ "T8107D 50", nullptr, { 0x0464FC, 0x046210, 0 }, { 0x3A888889, 0x44200000 } }, // Re-Volt (PAL) Code 1 is a render fix
{ "MK-5119250", nullptr, { 0x0C5EB4, 0 }, { 0x3A888889 } }, // Rez (PAL)
{ "T15122N", nullptr, { 0x8E7A80, 0x8E7AB4, 0 }, { 0x43E10000, 0x3FAAAAAB } }, // Ring, The - Terror's Realm (USA)
{ "MK-51010", nullptr, { 0x1A4D2C, 0x1A4D5C, 0 }, { 0x43F00000, 0x3F400000 } }, // Rippin' Riders (USA)
{ "HDR-0044", nullptr, { 0x298A94, 0x298AC4, 0 }, { 0x43F00000, 0x3F400000 } }, // Roommania #203 (JP)
{ "MK-5109250", nullptr, { 0x29E6C4, 0 }, { 0x3F400000 } }, // Samba De Amigo (PAL)
{ "T41301N", nullptr, { 0x77A178, 0 }, { 0x3F400000 } }, // Seventh Cross Evolution (USA)
{ "T8104D 58", nullptr, { 0x2C03F8, 0 }, { 0x44558000 } }, // Shadow Man (PAL)
{ "T-8106N", nullptr, { 0x2C03F4, 0 }, { 0x3F400000 } }, // Shadow Man (USA)
{ "MK-51048", nullptr, { 0x4AA4DC, 0x2B4E30, 0 }, { 0x3F400000, 0x3F400000 } }, // Seaman (USA)
{ "MK-5105350", nullptr, { 0x5D613C, 0 }, { 0x3F400000 } }, // Sega GT (PAL)
{ "MK-51096", nullptr, { 0x495050, 0 }, { 0x43700000 } }, // Sega Marine Fishing (USA)
// { "MK-51019", nullptr, { 0xB83A48, 0 }, { 0x3F400000 } }, // Sega Rally 2 (USA) not working?
// { "HDR0010", nullptr, { 0xBD9BA0, 0 }, { 0x3F400000 } }, // Sega Rally 2 (JP) not working?
{ "HDR-0151", nullptr, { 0xAF57DC, 0xAF580C, 0x2122A0, 0 },
{ "T8107D 50", nullptr, { 0x0464FC, 0x046210 }, { 0x3A888889, 0x44200000 } }, // Re-Volt (PAL) Code 1 is a render fix
{ "MK-5119250", nullptr, { 0x0C5EB4 }, { 0x3A888889 } }, // Rez (PAL)
{ "T15122N", nullptr, { 0x8E7A80, 0x8E7AB4 }, { 0x43E10000, 0x3FAAAAAB } }, // Ring, The - Terror's Realm (USA)
{ "MK-51010", nullptr, { 0x1A4D2C, 0x1A4D5C }, { 0x43F00000, 0x3F400000 } }, // Rippin' Riders (USA)
{ "HDR-0044", nullptr, { 0x298A94, 0x298AC4 }, { 0x43F00000, 0x3F400000 } }, // Roommania #203 (JP)
{ "MK-5109250", nullptr, { 0x29E6C4 }, { 0x3F400000 } }, // Samba De Amigo (PAL)
{ "T41301N", nullptr, { 0x77A178 }, { 0x3F400000 } }, // Seventh Cross Evolution (USA)
{ "T8104D 58", nullptr, { 0x2C03F8 }, { 0x44558000 } }, // Shadow Man (PAL)
{ "T-8106N", nullptr, { 0x2C03F4 }, { 0x3F400000 } }, // Shadow Man (USA)
{ "MK-51048", nullptr, { 0x4AA4DC, 0x2B4E30 }, { 0x3F400000, 0x3F400000 } }, // Seaman (USA)
{ "MK-5105350", nullptr, { 0x5D613C }, { 0x3F400000 } }, // Sega GT (PAL)
{ "MK-51096", nullptr, { 0x495050 }, { 0x43700000 } }, // Sega Marine Fishing (USA)
// { "MK-51019", nullptr, { 0xB83A48 }, { 0x3F400000 } }, // Sega Rally 2 (USA) not working?
// { "HDR0010", nullptr, { 0xBD9BA0 }, { 0x3F400000 } }, // Sega Rally 2 (JP) not working?
{ "HDR-0151", nullptr, { 0xAF57DC, 0xAF580C, 0x2122A0 },
{ 0x43F00000, 0x3F400000, 0x3F400000 } }, // SGGG – Segagaga (JP)
{ "MK-5105950", nullptr, { 0x231EF8, 0x1EF370, 0 }, { 0x43800000, 0x7C1EF400 } }, // Shenmue (PAL) code 1 reduces clipping
{ "MK-51059", nullptr, { 0x230250, 0 }, { 0x43800000 } }, // Shenmue (USA) Clipping
{ "HDR-0016", nullptr, { 0x22E8A0, 0x1EBE70, 0 }, { 0x43800000, 0x7C1EBF00 } }, // Shenmue (JP) code 1 reduces clipping
{ "MK-5118450", nullptr, { 0x31186C, 0 }, { 0x43800000 } }, // Shenmue II (PAL) 01160FF4 0000E100 for black bars in cutscenes
{ "MK-5105950", nullptr, { 0x231EF8, 0x1EF370 }, { 0x43800000, 0x7C1EF400 } }, // Shenmue (PAL) code 1 reduces clipping
{ "MK-51059", nullptr, { 0x230250 }, { 0x43800000 }, { 0x43a00000 } }, // Shenmue (USA) Clipping
{ "HDR-0016", nullptr, { 0x22E8A0, 0x1EBE70 }, { 0x43800000, 0x7C1EBF00 } }, // Shenmue (JP) code 1 reduces clipping
{ "MK-5118450", nullptr, { 0x31186C }, { 0x43800000 } }, // Shenmue II (PAL) 01160FF4 0000E100 for black bars in cutscenes
// Shenmue II (PAL) Alternative code without clipping or black bars. Might be demanding on real hardware.
// 02311880 C3A00000, 0227E198 35AA359E, 01160FF4 0000E100
{ "HDR-0164", nullptr, { 0x30D67C, 0 }, { 0x43700000 } }, // Shenmue II (JP) Clipping
{ "T9505D", nullptr, { 0xD1FB14, 0x096A4C, 0 }, { 0x3F400000, 0x3FAAAAAB } }, // Silent Scope (PAL) Choose 60Hz in game options
{ "MK-51052", " E ", { 0x502A84, 0 }, { 0x3F400000 } }, // Skies of Arcadia (PAL)
{ "MK-51052", " U ", { 0x599158, 0 }, { 0x3F400000 } }, // Skies of Arcadia (USA)
{ "T15104D 50", nullptr, { 0x17EF68, 0 }, { 0x43F00010 } }, // Slave Zero (PAL) Widescreen, but a bit zoomed in
{ "MK-5101050", nullptr, { 0x1A50EC, 0x1A511C, 0 }, { 0x43F00000, 0x3F400000 } }, // Snow Surfers (PAL)
{ "MK-5100050", nullptr, { 0x88F528, 0x88F55C, 0 }, { 0x43F00000, 0x3FA66666 } }, // Sonic Adventure (PAL)
{ "MK-51000", nullptr, { 0x88F5E8, 0x88F61C, 0 }, { 0x43F00000, 0x3FAAAAAB } }, // Sonic Adventure (USA)
{ "MK-51117", nullptr, { 0x28DEF8, 0x28DF28, 0 }, { 0x43F00000, 0x3f400000 } }, // Sonic Adventure 2 (USA)
{ "HDR-0165", nullptr, { 0x28DF28, 0x28DEF8, 0 }, { 0x3F400000, 0x43F00000 } }, // Sonic Adventure 2 (JP)
{ "MK-51060", nullptr, { 0x112A2C, 0 }, { 0x3F400000 } }, // Sonic Shuffle (US)
{ "MK-5106050", nullptr, { 0x110B4C, 0 }, { 0x3F400000 } }, // Sonic Shuffle (PAL)
{ "T9103M", nullptr, { 0x25C714, 0x25C744, 0 }, { 0x43F00000, 0x3F400000 } }, // Sorcerian - Shichisei Mahou no Shito
{ "T1401D 50", nullptr, { 0x2D6138, 0 }, { 0x3F400000 } }, // Soul Calibur (PAL)
{ "T1401N", nullptr, { 0x266C28, 0 }, { 0x3F400000 } }, // Soul Calibur (USA)
{ "T36802N", " E ", { 0x129FA0, 0x12A9BC, 0x1C9FDC, 0 },
{ "HDR-0164", nullptr, { 0x30D67C }, { 0x43700000 } }, // Shenmue II (JP) Clipping
{ "T9505D", nullptr, { 0xD1FB14, 0x096A4C }, { 0x3F400000, 0x3FAAAAAB } }, // Silent Scope (PAL) Choose 60Hz in game options
{ "MK-51052", " E ", { 0x502A84 }, { 0x3F400000 } }, // Skies of Arcadia (PAL)
{ "MK-51052", " U ", { 0x599158 }, { 0x3F400000 } }, // Skies of Arcadia (USA)
{ "T15104D 50", nullptr, { 0x17EF68 }, { 0x43F00010 } }, // Slave Zero (PAL) Widescreen, but a bit zoomed in
{ "MK-5101050", nullptr, { 0x1A50EC, 0x1A511C }, { 0x43F00000, 0x3F400000 } }, // Snow Surfers (PAL)
{ "MK-5100050", nullptr, { 0x88F528, 0x88F55C }, { 0x43F00000, 0x3FA66666 } }, // Sonic Adventure (PAL)
{ "MK-51000", nullptr, { 0x88F5E8, 0x88F61C }, { 0x43F00000, 0x3FAAAAAB } }, // Sonic Adventure (USA)
{ "MK-51117", nullptr, { 0x28DEF8, 0x28DF28 }, { 0x43F00000, 0x3f400000 } }, // Sonic Adventure 2 (USA)
{ "HDR-0165", nullptr, { 0x28DF28, 0x28DEF8 }, { 0x3F400000, 0x43F00000 } }, // Sonic Adventure 2 (JP)
{ "MK-51060", nullptr, { 0x112A2C }, { 0x3F400000 } }, // Sonic Shuffle (US)
{ "MK-5106050", nullptr, { 0x110B4C }, { 0x3F400000 } }, // Sonic Shuffle (PAL)
{ "T9103M", nullptr, { 0x25C714, 0x25C744 }, { 0x43F00000, 0x3F400000 } }, // Sorcerian - Shichisei Mahou no Shito
{ "T1401D 50", nullptr, { 0x2D6138 }, { 0x3F400000 } }, // Soul Calibur (PAL)
{ "T1401N", nullptr, { 0x266C28 }, { 0x3F400000 } }, // Soul Calibur (USA)
{ "T36802N", " E ", { 0x129FA0, 0x12A9BC, 0x1C9FDC },
{ 0x3EF55555, 0x3EF55555, 0x000000F0 } }, // Soul Reaver (PAL) Code 2 is a Render Fix
{ "HDR-0190", nullptr, { 0x14D3E0, 0 }, { 0x3F400000 } }, // Space Channel 5 Part 2 (JP)
{ "T1216M", nullptr, { 0x017C38, 0x17F00, 0 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.003 (JP)
{ "T1216N", nullptr, { 0x017C58, 0x17F20, 0 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (US)
{ "T36816D 50", nullptr, { 0x017C78, 0x17F40, 0 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (EU)
{ "HDR-0190", nullptr, { 0x14D3E0 }, { 0x3F400000 } }, // Space Channel 5 Part 2 (JP)
{ "T1216M", nullptr, { 0x017C38, 0x17F00 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.003 (JP)
{ "T1216N", nullptr, { 0x017C58, 0x17F20 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (US)
{ "T36816D 50", nullptr, { 0x017C78, 0x17F40 }, { 0x3A99999A, 0x3A99999A } }, // Spawn - In the Demon's Hand v1.000 (EU)
// Star Wars Episode I Racer (USA)
// Code 1-4 removes the black bars on top and bottom in FMV
{ "T23001N", nullptr, { 0x17AE20, 0x29A96C, 0x29A98C, 0x29A9AC, 0x29A9CC, 0 },
{ "T23001N", nullptr, { 0x17AE20, 0x29A96C, 0x29A98C, 0x29A9AC, 0x29A9CC },
{ 0x3F400000, 0x42900000, 0x42900000, 0x43CE0000, 0x43CE0000 } },
{ "T40206N", nullptr, { 0x43296C, 0 }, { 0x3F400000, 0 } }, // Super Magnetic Neo (US)
{ "T40206D 50", nullptr, { 0x43E34C, 0 }, { 0x3F400000, 0 } }, // Super Magnetic Neo (EU)
// { "T7014D 50", nullptr, { 0xE2B234, 0 }, { 0x3F800000 } }, // Super Runabout (PAL) doesn't work?
{ "T17721D 50", nullptr, { 0x45CED4, 0 }, { 0x3F400000 } }, // Surf Rocket Racers (PAL) alt: 021EBF40 3F400000
{ "T17703D 50", nullptr, { 0xCD8950, 0 }, { 0x3F111111 } }, // Suzuki Alstare Extreme Racing
{ "T36807D 05", nullptr, { 0x140F74, 0x140FA4, 0 }, { 0x43FA0000, 0x3F400000 } }, // Sword of Bersek (PAL)
{ "T-36805N", nullptr, { 0x13F1C4, 0x13F194, 0 }, { 0x3F400000, 0x43F00000 } }, // Sword of Bersek (USA)
{ "MK-51186", nullptr, { 0x4A19B0, 0 }, { 0x43700000 } }, // Tennis 2K2 (USA)
{ "T15123N", nullptr, { 0x29B7BC, 0 }, { 0x3F400000 } }, // Test Drive Le Mans (USA) doesn't work?
{ "T20801M", nullptr, { 0x1AAC80, 0x1AACB0, 0 }, { 0x43F00000, 0x3F400000 } }, // Tetris 4D (JP)
{ "MK-5101153", nullptr, { 0x14EFA8, 0x14EFD8, 0 }, { 0x43F00000, 0x3F400000 } }, // Timestalkers (PAL)
{ "T7009D50", nullptr, { 0x39173C, 0 }, { 0x3F400000 } }, // Tech Romancer (PAL)
{ "T35402M", nullptr, { 0x315370, 0x3153A0, 0 }, { 0x43F00000, 0x3F400000 } }, // Tokyo Bus Guide (JP) doesn't work?
{ "T40201D 50", nullptr, { 0x1D9F10, 0 }, { 0x3F400000 } }, // Tokyo Highway Challenge (PAL)
{ "T40210D 50", nullptr, { 0x21E4F8, 0 }, { 0x43700000 } }, // Tokyo Highway Challenge 2 (PAL)
{ "xxxxxxxxxx", nullptr, { 0x21DEF8, 0 }, { 0x3F400000 } }, // Tokyo Street Racer 2 (USA)
// { "T36804D05", nullptr, { 0xB75E28, 0 }, { 0x3EC00000 } }, // Tomb Raider: The Last Revelation (UK) (PAL) clipping, use hex patch instead
{ "T13008D 05", nullptr, { 0x1D7C20, 0 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (PAL)
{ "T13006N", nullptr, { 0x1D77A0, 0 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (USA)
{ "MK-5102050", nullptr, { 0x0D592C, 0 }, { 0x3FD00000 } }, // Toy Commander (PAL)
{ "xxxxxxxxxx", nullptr, { 0x469FCC, 0x469FFC, 0 }, { 0x44700000, 0x3F400000 } }, // Toyota Doricatch Series: Land Cruiser 100/Cygnus
{ "MK-5109505", nullptr, { 0x1B2718, 0 }, { 0x3F400000 } }, // UEFA Dream Soccer (PAL)
{ "T40203D 50", nullptr, { 0x1D74E8, 0x1D7518, 0 }, { 0x43F00000, 0x3F400000 } }, // Ultimate Fighting Championship (PAL)
{ "T40204N", nullptr, { 0x1A9684, 0 }, { 0x3F400000 } }, // Ultimate Fighting Championship (USA) problems with cam in game
{ "T-8110D-50", nullptr, { 0x0C6B90, 0x0C6B94, 0 }, { 0x43F00000, 0x43870000 } }, // Vanishing Point (PAL)
// { "MK-5109450", nullptr, { 0x244134, 0x7A73B8, 0x7830D8, 0x7A74B8, 0x783138, 0x7A85A0, 0x6C7928, 0x6C7930, 0x6C7948, 0x6C7950, 0 },
{ "T40206N", nullptr, { 0x43296C }, { 0x3F400000 } }, // Super Magnetic Neo (US)
{ "T40206D 50", nullptr, { 0x43E34C }, { 0x3F400000 } }, // Super Magnetic Neo (EU)
// { "T7014D 50", nullptr, { 0xE2B234 }, { 0x3F800000 } }, // Super Runabout (PAL) doesn't work?
{ "T17721D 50", nullptr, { 0x45CED4 }, { 0x3F400000 } }, // Surf Rocket Racers (PAL) alt: 021EBF40 3F400000
{ "T17703D 50", nullptr, { 0xCD8950 }, { 0x3F111111 } }, // Suzuki Alstare Extreme Racing
{ "T36807D 05", nullptr, { 0x140F74, 0x140FA4 }, { 0x43FA0000, 0x3F400000 } }, // Sword of Bersek (PAL)
{ "T-36805N", nullptr, { 0x13F1C4, 0x13F194 }, { 0x3F400000, 0x43F00000 } }, // Sword of Bersek (USA)
{ "MK-51186", nullptr, { 0x4A19B0 }, { 0x43700000 } }, // Tennis 2K2 (USA)
{ "T15123N", nullptr, { 0x29B7BC }, { 0x3F400000 } }, // Test Drive Le Mans (USA) doesn't work?
{ "T20801M", nullptr, { 0x1AAC80, 0x1AACB0 }, { 0x43F00000, 0x3F400000 } }, // Tetris 4D (JP)
{ "MK-5101153", nullptr, { 0x14EFA8, 0x14EFD8 }, { 0x43F00000, 0x3F400000 } }, // Timestalkers (PAL)
{ "T7009D50", nullptr, { 0x39173C }, { 0x3F400000 } }, // Tech Romancer (PAL)
{ "T35402M", nullptr, { 0x315370, 0x3153A0 }, { 0x43F00000, 0x3F400000 } }, // Tokyo Bus Guide (JP) doesn't work?
{ "T40201D 50", nullptr, { 0x1D9F10 }, { 0x3F400000 } }, // Tokyo Highway Challenge (PAL)
{ "T40210D 50", nullptr, { 0x21E4F8 }, { 0x43700000 } }, // Tokyo Highway Challenge 2 (PAL)
{ "xxxxxxxxxx", nullptr, { 0x21DEF8 }, { 0x3F400000 } }, // Tokyo Street Racer 2 (USA)
// { "T36804D05", nullptr, { 0xB75E28 }, { 0x3EC00000 } }, // Tomb Raider: The Last Revelation (UK) (PAL) clipping, use hex patch instead
{ "T13008D 05", nullptr, { 0x1D7C20 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (PAL)
{ "T13006N", nullptr, { 0x1D77A0 }, { 0x3FA66666 } }, // Tony Hawk's Pro Skater 2 (USA)
{ "MK-5102050", nullptr, { 0x0D592C }, { 0x3FD00000 } }, // Toy Commander (PAL)
{ "xxxxxxxxxx", nullptr, { 0x469FCC, 0x469FFC }, { 0x44700000, 0x3F400000 } }, // Toyota Doricatch Series: Land Cruiser 100/Cygnus
{ "MK-5109505", nullptr, { 0x1B2718 }, { 0x3F400000 } }, // UEFA Dream Soccer (PAL)
{ "T40203D 50", nullptr, { 0x1D74E8, 0x1D7518 }, { 0x43F00000, 0x3F400000 } }, // Ultimate Fighting Championship (PAL)
{ "T40204N", nullptr, { 0x1A9684 }, { 0x3F400000 } }, // Ultimate Fighting Championship (USA) problems with cam in game
{ "T-8110D-50", nullptr, { 0x0C6B90, 0x0C6B94 }, { 0x43F00000, 0x43870000 } }, // Vanishing Point (PAL)
// { "MK-5109450", nullptr, { 0x244134, 0x7A73B8, 0x7830D8, 0x7A74B8, 0x783138, 0x7A85A0, 0x6C7928, 0x6C7930, 0x6C7948, 0x6C7950 },
//crash { 0x43F00000, 0x3F9C932E, 0x3F9C932E, 0x3F9C932E, 0x3F9C932E, 0x3F400000, 0, 0, 0, 0 } }, // Virtua Athlete 2K (PAL)
{ "MK-5100150", nullptr, { 0x19D718, 0 }, { 0x43700000 } }, // Virtua Fighter 3 TB (PAL)
{ "HDR-0002", nullptr, { 0x199FB0, 0 }, { 0x43700000 } }, // Virtua Fighter 3 TB (JP)
{ "MK-5105450", nullptr, { 0x456378, 0 }, { 0x43700000 } }, // Virtua Tennis (v1.001) (PAL)
{ "MK-51054", nullptr, { 0x450A90, 0 }, { 0x43700000 } }, // Virtua Tennis (USA)
{ "MK-5118650", nullptr, { 0x4A4A20, 0 }, { 0x43700000 } }, // Virtua Tennis 2 (PAL)
// { "T0000", nullptr, { 0x3A514C, 0x3A6170, 0 }, { 0x3F400000, 0x00000356 } }, // Volgarr the Viking. Not working
{ "xxxxxxxxxx", nullptr, { 0x20BB68, 0x1ACBD0, 0x1B9ADC, 0 }, // Code 1 reduces clipping. Code 2 fixes the clock.
{ "MK-5100150", nullptr, { 0x19D718 }, { 0x43700000 } }, // Virtua Fighter 3 TB (PAL)
{ "HDR-0002", nullptr, { 0x199FB0 }, { 0x43700000 } }, // Virtua Fighter 3 TB (JP)
{ "MK-5105450", nullptr, { 0x456378 }, { 0x43700000 } }, // Virtua Tennis (v1.001) (PAL)
{ "MK-51054", nullptr, { 0x450A90 }, { 0x43700000 } }, // Virtua Tennis (USA)
{ "MK-5118650", nullptr, { 0x4A4A20 }, { 0x43700000 } }, // Virtua Tennis 2 (PAL)
// { "T0000", nullptr, { 0x3A514C, 0x3A6170 }, { 0x3F400000, 0x00000356 } }, // Volgarr the Viking. Not working
{ "xxxxxxxxxx", nullptr, { 0x20BB68, 0x1ACBD0, 0x1B9ADC }, // Code 1 reduces clipping. Code 2 fixes the clock.
{ 0x43700000, 0x7C1ACC60, 0x3F400000 } }, // What's Shenmue (JP)
{ "T40504D 50", nullptr, { 0x75281C, 0 }, { 0x3F400000 } }, // Wetrix+ (PAL) not working?
{ "MK-51152", nullptr, { 0x014E90, 0 }, { 0x43700000 } }, // World Series Baseball 2K2 (USA)
{ "T20401M", nullptr, { 0x323CB0, 0x1ACBD0, 0x1B9ADC, 0 }, // Code 1 reduces clipping. Code 2 fixes the HUD.
{ "T40504D 50", nullptr, { 0x75281C }, { 0x3F400000 } }, // Wetrix+ (PAL) not working?
{ "MK-51152", nullptr, { 0x014E90 }, { 0x43700000 } }, // World Series Baseball 2K2 (USA)
{ "T20401M", nullptr, { 0x323CB0, 0x1ACBD0, 0x1B9ADC }, // Code 1 reduces clipping. Code 2 fixes the HUD.
{ 0x43700000, 0x1ACC60, 0x3F400000 } }, // Zero Gunner 2 (JP)
{ "MK-5103850", nullptr, { 0x9484E8, 0 }, { 0x43700000 } }, // Zombie Revenge (PAL)
{ "MK-51038", nullptr, { 0x948058, 0 }, { 0x43700000 } }, // Zombie Revenge (USA)
{ "HDR-0026", nullptr, { 0x948B18, 0 }, { 0x43700000 } }, // Zombie Revenge (JP)
{ "T43301M", nullptr, { 0x4B0218, 0 }, { 0x3F400000 } }, // Zusar Vasar (JP)
{ "MK-5103850", nullptr, { 0x9484E8 }, { 0x43700000 } }, // Zombie Revenge (PAL)
{ "MK-51038", nullptr, { 0x948058 }, { 0x43700000 } }, // Zombie Revenge (USA)
{ "HDR-0026", nullptr, { 0x948B18 }, { 0x43700000 } }, // Zombie Revenge (JP)
{ "T43301M", nullptr, { 0x4B0218 }, { 0x3F400000 } }, // Zusar Vasar (JP)
{ nullptr },
};
const WidescreenCheat CheatManager::naomi_widescreen_cheats[] =
{
{ "KNIGHTS OF VALOUR THE 7 SPIRITS", nullptr, { 0x475B70, 0x475B40, 0 }, { 0x3F400000, 0x43F00000 } },
{ "Dolphin Blue", nullptr, { 0x3F2E2C, 0x3F2190, 0x3F2E6C, 0x3F215C, 0 },
{ "KNIGHTS OF VALOUR THE 7 SPIRITS", nullptr, { 0x475B70, 0x475B40 }, { 0x3F400000, 0x43F00000 } },
{ "Dolphin Blue", nullptr, { 0x3F2E2C, 0x3F2190, 0x3F2E6C, 0x3F215C },
{ 0x43B90000, 0x3FAA9FBE, 0x43B90000, 0x43F00000 } },
{ "METAL SLUG 6", nullptr, { 0xE93478, 0xE9347C, 0 }, { 0x3F400000, 0x3F8872B0 } },
{ "TOY FIGHTER", nullptr, { 0x133E58, 0 }, { 0x43700000 } },
{ "METAL SLUG 6", nullptr, { 0xE93478, 0xE9347C }, { 0x3F400000, 0x3F8872B0 } },
{ "TOY FIGHTER", nullptr, { 0x133E58 }, { 0x43700000 } },
{ "LUPIN THE THIRD -THE SHOOTING-", nullptr, { 0x045490 }, { 0x3F400000 } },
{ "VF4 FINAL TUNED JAPAN", nullptr, { 0x02B834, 0x0AFB90 }, { 0x3FE38E39, 0x3FE38E39 } },
{ "DYNAMITE DEKA EX", nullptr, { 0x0E3598, 0x0C8E84 }, { 0x3FE38E38, 0x3FE38E38 } },
{ "DEAD OR ALIVE 2", "doa2m", { 0x085B5C, 0x086AE8 }, { 0x3FE38E39, 0x3FE38E39 } },
{ "SLASHOUT JAPAN VERSION", nullptr, { 0x3DDBE4 }, { 0x43CFDC86 } },
{ "SPIKERS BATTLE JAPAN VERSION", nullptr, { 0x3626C4 }, { 0x43A551B0 } },
{ " 18WHEELER", "18wheelr", { 0x5C64A8 }, { 0x43700000 } },
{ "BEACH SPIKERS JAPAN", nullptr, { 0x065A7C }, { 0x44558000 } },
{ "GUN SPIKE", nullptr, { 0x21A94 }, { 0x3FE38E39 } },
{ "INITIAL D Ver.3", "initdv3e", { 0x1D0B34 }, { 0x3FE38E39 } },
{ "AIRLINE PILOTS IN JAPAN", "alpilotj", { 0x1D62550 }, { 0x43700000 } },
{ "MONKEY BALL JAPAN VERSION", nullptr, { 0x345B4, 0x45244, 0x454CC }, { 0x3FE38E39, 0x3FE38E39, 0x3FE38E39 } },
{ "ZOMBIE REVENGE IN JAPAN", "zombrvn", { 0x7A4808 }, { 0x43700000 } },
{ "ZOMBIE REVENGE IN JAPAN", "zombrvno", { 0x7A2E50 }, { 0x43700000 } },
{ nullptr },
};
CheatManager cheatManager;
static void vblankCallback(Event event, void *param)
{
((CheatManager *)param)->apply();
}
void CheatManager::setActive(bool active)
{
this->active = active;
if (active || widescreen_cheat != nullptr)
EventManager::listen(Event::VBlank, vblankCallback, this);
else
EventManager::unlisten(Event::VBlank, vblankCallback, this);
}
void CheatManager::loadCheatFile(const std::string& filename)
{
#ifndef LIBRETRO
@@ -349,7 +379,7 @@ void CheatManager::loadCheatFile(const std::string& filename)
if (cheat.type != Cheat::Type::disabled)
cheats.push_back(cheat);
}
active = !cheats.empty();
setActive(!cheats.empty());
INFO_LOG(COMMON, "%d cheats loaded", (int)cheats.size());
cfgSaveStr("cheats", gameId, filename);
#endif
@@ -357,51 +387,66 @@ void CheatManager::loadCheatFile(const std::string& filename)
void CheatManager::reset(const std::string& gameId)
{
widescreen_cheat = nullptr;
if (this->gameId != gameId)
{
cheats.clear();
active = false;
setActive(false);
this->gameId = gameId;
#ifndef LIBRETRO
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
if (!cheatFile.empty())
loadCheatFile(cheatFile);
#endif
}
widescreen_cheat = nullptr;
if (!config::WidescreenGameHacks)
return;
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
{
for (int i = 0; widescreen_cheats[i].game_id != nullptr; i++)
if (gameId == "VF4 FINAL TUNED JAPAN")
{
if (!strcmp(gameId.c_str(), widescreen_cheats[i].game_id)
&& (widescreen_cheats[i].area_or_version == nullptr
|| !strncmp(ip_meta.area_symbols, widescreen_cheats[i].area_or_version, sizeof(ip_meta.area_symbols))
|| !strncmp(ip_meta.product_version, widescreen_cheats[i].area_or_version, sizeof(ip_meta.product_version))))
{
widescreen_cheat = &widescreen_cheats[i];
NOTICE_LOG(COMMON, "Applying widescreen hack to game %s", gameId.c_str());
break;
}
setActive(true);
cheats.emplace_back(Cheat::Type::setValue, "Skip DIMM version check", true, 16, 0x0007f486, 0xe001); // mov #1, r0
cheats.back().builtIn = true;
}
}
else
if (config::WidescreenGameHacks)
{
for (int i = 0; naomi_widescreen_cheats[i].game_id != nullptr; i++)
if (settings.platform.isConsole())
{
if (!strcmp(gameId.c_str(), naomi_widescreen_cheats[i].game_id))
for (int i = 0; widescreen_cheats[i].game_id != nullptr; i++)
{
widescreen_cheat = &naomi_widescreen_cheats[i];
NOTICE_LOG(COMMON, "Applying widescreen hack to game %s", gameId.c_str());
break;
if (!strcmp(gameId.c_str(), widescreen_cheats[i].game_id)
&& (widescreen_cheats[i].area_or_version == nullptr
|| !strncmp(ip_meta.area_symbols, widescreen_cheats[i].area_or_version, sizeof(ip_meta.area_symbols))
|| !strncmp(ip_meta.product_version, widescreen_cheats[i].area_or_version, sizeof(ip_meta.product_version))
|| !strncmp(ip_meta.software_name, widescreen_cheats[i].area_or_version, sizeof(ip_meta.software_name))))
{
widescreen_cheat = &widescreen_cheats[i];
NOTICE_LOG(COMMON, "Applying widescreen hack to game %s", gameId.c_str());
break;
}
}
}
else
{
std::string romName = get_file_basename(settings.content.path);
size_t folder_pos = get_last_slash_pos(romName);
if (folder_pos != std::string::npos)
romName = romName.substr(folder_pos + 1);
for (int i = 0; naomi_widescreen_cheats[i].game_id != nullptr; i++)
{
if (!strcmp(gameId.c_str(), naomi_widescreen_cheats[i].game_id)
&& (naomi_widescreen_cheats[i].area_or_version == nullptr
|| !strcmp(romName.c_str(), naomi_widescreen_cheats[i].area_or_version)))
{
widescreen_cheat = &naomi_widescreen_cheats[i];
NOTICE_LOG(COMMON, "Applying widescreen hack to game %s", gameId.c_str());
break;
}
}
}
if (widescreen_cheat != nullptr)
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
verify(widescreen_cheat->addresses[i] < RAM_SIZE);
}
if (widescreen_cheat == nullptr)
return;
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
verify(widescreen_cheat->addresses[i] < RAM_SIZE);
setActive(active);
}
u32 CheatManager::readRam(u32 addr, u32 bits)
@@ -440,7 +485,12 @@ void CheatManager::apply()
if (widescreen_cheat != nullptr)
{
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
writeRam(widescreen_cheat->addresses[i], widescreen_cheat->values[i], 32);
{
u32 address = widescreen_cheat->addresses[i];
u32 curVal = readRam(address, 32);
if (curVal != widescreen_cheat->values[i] && (widescreen_cheat->origValues[i] == 0 || widescreen_cheat->origValues[i] == curVal))
writeRam(address, widescreen_cheat->values[i], 32);
}
}
if (active && !settings.network.online)
{
@@ -495,9 +545,9 @@ void CheatManager::apply()
u32 address = cheat.address;
for (u32 repeat = 0; repeat < cheat.repeatCount; repeat++)
{
u32 curVal = readRam(address, cheat.size);
if (cheat.size < 8)
{
u8 curVal = readRam(address, 8);
for (int i = 0; i < 8; i++)
{
int bitmask = 1 << i;
@@ -506,7 +556,8 @@ void CheatManager::apply()
valueToSet = (valueToSet & ~bitmask) | (curVal & bitmask);
}
}
writeRam(address, valueToSet, cheat.size);
if (curVal != valueToSet)
writeRam(address, valueToSet, cheat.size);
address += cheat.repeatAddressIncrement * cheat.size / 8;
valueToSet += cheat.repeatValueIncrement;
}
@@ -733,7 +784,7 @@ void CheatManager::addGameSharkCheat(const std::string& name, const std::string&
throw FlycastException("Unsupported cheat type");
}
}
active = !cheats.empty();
setActive(!cheats.empty());
#ifndef LIBRETRO
std::string path = cfgLoadStr("cheats", gameId, "");
if (path == "")
@@ -750,10 +801,11 @@ void CheatManager::saveCheatFile(const std::string& filename)
#ifndef LIBRETRO
emucfg::ConfigFile cfg;
cfg.set_int("", "cheats", cheats.size());
int i = 0;
for (const Cheat& cheat : cheats)
{
if (cheat.builtIn)
continue;
std::string prefix = "cheat" + std::to_string(i) + "_";
cfg.set_int("", prefix + "address", cheat.address);
cfg.set_int("", prefix + "address_bit_position", cheat.valueMask);
@@ -793,6 +845,7 @@ void CheatManager::saveCheatFile(const std::string& filename)
cfg.set_int("", prefix + "repeat_add_to_address", cheat.repeatAddressIncrement);
i++;
}
cfg.set_int("", "cheats", i);
FILE *fp = nowide::fopen(filename.c_str(), "w");
if (fp == nullptr)
throw FlycastException("Can't save cheat file");
+22 -10
View File
@@ -27,6 +27,7 @@ struct WidescreenCheat
const char *area_or_version;
u32 addresses[16];
u32 values[16];
u32 origValues[16];
};
struct Cheat
@@ -42,17 +43,27 @@ struct Cheat
runNextIfLt,
copy
};
Type type = Type::disabled;
Type type;
std::string description;
bool enabled = false;
u32 size = 0;
u32 address = 0;
u32 value = 0;
u8 valueMask = 0;
u32 repeatCount = 1;
u32 repeatValueIncrement = 0;
u32 repeatAddressIncrement = 0;
u32 destAddress = 0;
bool enabled;
u32 size;
u32 address;
u32 value;
u8 valueMask;
u32 repeatCount;
u32 repeatValueIncrement;
u32 repeatAddressIncrement;
u32 destAddress;
bool builtIn;
Cheat(Type type = Type::disabled, const std::string& description = "", bool enabled = false, u32 size = 0, u32 address = 0,
u32 value = 0, u8 valueMask = 0, u32 repeatCount = 1, u32 repeatValueIncrement = 0,
u32 repeatAddressIncrement = 0, u32 destAddress = 0, bool builtIn = false)
: type(type), description(description), enabled(enabled), size(size), address(address), value(value), valueMask(valueMask),
repeatCount(repeatCount), repeatValueIncrement(repeatValueIncrement), repeatAddressIncrement(repeatAddressIncrement),
destAddress(destAddress), builtIn(builtIn)
{
}
};
class CheatManager
@@ -73,6 +84,7 @@ public:
private:
u32 readRam(u32 addr, u32 bits);
void writeRam(u32 addr, u32 value, u32 bits);
void setActive(bool active);
static const WidescreenCheat widescreen_cheats[];
static const WidescreenCheat naomi_widescreen_cheats[];
+1 -1
View File
@@ -247,7 +247,7 @@ public:
void restart()
{
emu.unloadGame();
emu.loadGame(settings.content.path);
emu.loadGame(settings.content.path.c_str());
emu.start();
}
+1
View File
@@ -825,6 +825,7 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,
ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
ImGuiWindowFlags_DragScrolling = 1 << 21, // Allow scrolling by dragging content
// [Internal]
ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
+8 -4
View File
@@ -645,10 +645,16 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
if (delta.x != 0.f || delta.y != 0.f)
{
ClearActiveID();
// Find an ancestor window that allows drag scrolling.
ImGuiWindow *scrollableWindow = window;
while ((scrollableWindow->Flags & ImGuiWindowFlags_ChildWindow) && scrollableWindow->ScrollMax.x == 0.0f && scrollableWindow->ScrollMax.y == 0.0f)
while (scrollableWindow != nullptr
&& (scrollableWindow->Flags & ImGuiWindowFlags_ChildWindow)
&& !(scrollableWindow->Flags & ImGuiWindowFlags_DragScrolling)
&& scrollableWindow->ScrollMax.x == 0.0f
&& scrollableWindow->ScrollMax.y == 0.0f)
scrollableWindow = scrollableWindow->ParentWindow;
scrollableWindow->DragScrolling = true;
if (scrollableWindow != nullptr && (scrollableWindow->Flags & ImGuiWindowFlags_DragScrolling))
scrollableWindow->DragScrolling = true;
held = false;
pressed = false;
}
@@ -1706,8 +1712,6 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
SetItemDefaultFocus();
PopID();
}
// no drag scrolling on combo popup
GetCurrentWindow()->DragScrolling = false;
EndCombo();
return value_changed;
-28
View File
@@ -1,28 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9411c76e7..c48243e31 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1970,9 +1970,7 @@ elseif(APPLE)
endif()
if(SDL_VULKAN OR SDL_METAL OR SDL_RENDER_METAL)
- set(ORIG_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
- set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -ObjC")
- check_c_source_compiles("
+ check_objc_source_compiles("
#include <AvailabilityMacros.h>
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
@@ -1980,11 +1978,7 @@ elseif(APPLE)
#if (!TARGET_CPU_X86_64 && !TARGET_CPU_ARM64)
#error Metal doesn't work on this configuration
#endif
- int main(void) {
- return 0;
- }
- " HAVE_FRAMEWORK_METAL)
- set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
+ int main(void) {}" HAVE_FRAMEWORK_METAL)
if(HAVE_FRAMEWORK_METAL)
set(SDL_FRAMEWORK_METAL 1)
set(SDL_FRAMEWORK_QUARTZCORE 1)
+48 -22
View File
@@ -38,7 +38,6 @@
#include "hw/mem/mem_watch.h"
#include "network/net_handshake.h"
#include "rend/gui.h"
#include "lua/lua.h"
#include "network/naomi_network.h"
#include "serialize.h"
#include "hw/pvr/pvr.h"
@@ -48,7 +47,7 @@ settings_t settings;
static void loadSpecialSettings()
{
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isConsole())
{
std::string prod_id(ip_meta.product_number, sizeof(ip_meta.product_number));
prod_id = trim_trailing_ws(prod_id);
@@ -96,7 +95,7 @@ static void loadSpecialSettings()
// JSR (EU)
|| prod_id == "MK-5105850")
{
INFO_LOG(BOOT, "Enabling render to texture buffer for game %s", prod_id.c_str());
INFO_LOG(BOOT, "Enabling RTT Copy to VRAM for game %s", prod_id.c_str());
config::RenderToTextureBuffer.override(true);
}
if (prod_id == "HDR-0176" || prod_id == "RDC-0057")
@@ -194,17 +193,8 @@ static void loadSpecialSettings()
}
if (prod_id == "T9512N" // The Grinch (US)
|| prod_id == "T9503D" // The Grinch (EU)
|| prod_id == "T0000M" // Hell Gate FIXME
|| prod_id == "MK-51012" // Metropolis Street Racer (US)
|| prod_id == "MK-5102250" // Metropolis Street Racer (EU)
|| prod_id == "T-31101N" // Psychic Force 2012 (US)
|| prod_id == "T1101M" // Psychic Force 2012 (JP)
|| prod_id == "T-8106D-50" // Psychic Force 2012 (EU)
|| prod_id == "T-9707N" // San Francisco Rush 2049 (US)
|| prod_id == "T-9709D-50" // San Francisco Rush 2049 (EU)
|| prod_id == "MK-51146" // Sega Smashpack vol.1 (Sega Swirl)
|| prod_id == "MK-51152" // World Series Baseball 2K2
|| prod_id == "T20401M" // Zero Gunner
|| prod_id == "12502D-50" // Caesar's palace 2000 (EU)
|| prod_id == "T7001D 50" // Jimmy White's 2 Cueball
|| prod_id == "T17717D 50" // The Next Tetris (EU)
@@ -216,8 +206,19 @@ static void loadSpecialSettings()
NOTICE_LOG(BOOT, "Forcing real BIOS");
config::UseReios.override(false);
}
if (prod_id == "T-9707N" // San Francisco Rush 2049 (US)
|| prod_id == "MK-51146") // Sega Smash Pack - Volume 1
{
NOTICE_LOG(BOOT, "Forcing NTSC broadcasting");
config::Broadcast.override(0);
}
else if (prod_id == "T-9709D-50") // San Francisco Rush 2049 (EU)
{
NOTICE_LOG(BOOT, "Forcing PAL broadcasting");
config::Broadcast.override(1);
}
}
else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE)
else if (settings.platform.isArcade())
{
NOTICE_LOG(BOOT, "Game ID is [%s]", naomi_game_id);
if (!strcmp("SAMURAI SPIRITS 6", naomi_game_id))
@@ -230,6 +231,11 @@ static void loadSpecialSettings()
INFO_LOG(BOOT, "Enabling translucent depth multipass for game %s", naomi_game_id);
config::TranslucentPolygonDepthMask.override(true);
}
if (!strcmp(naomi_game_id, "BEACH SPIKERS JAPAN"))
{
INFO_LOG(BOOT, "Enabling RTT Copy to VRAM for game %s", naomi_game_id);
config::RenderToTextureBuffer.override(true);
}
// Input configuration
settings.input.JammaSetup = JVS::Default;
if (!strcmp("DYNAMIC GOLF", naomi_game_id)
@@ -255,7 +261,8 @@ static void loadSpecialSettings()
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
settings.input.JammaSetup = JVS::SegaMarineFishing;
}
else if (!strcmp("RINGOUT 4X4 JAPAN", naomi_game_id))
else if (!strcmp("RINGOUT 4X4 JAPAN", naomi_game_id)
|| !strcmp("VIRTUA ATHLETE", naomi_game_id))
{
INFO_LOG(BOOT, "Enabling specific JVS setup for game %s", naomi_game_id);
settings.input.JammaSetup = JVS::DualIOBoards4P;
@@ -337,7 +344,7 @@ void dc_reset(bool hard)
sh4_sched_reset(hard);
pvr::reset(hard);
libAICA_Reset(hard);
libARM_Reset(hard);
aicaarm::reset();
sh4_cpu.Reset(true);
mem_Reset(hard);
}
@@ -362,6 +369,13 @@ static void setPlatform(int platform)
settings.platform.bios_size = 2 * 1024 * 1024;
settings.platform.flash_size = 32 * 1024; // battery-backed ram
break;
case DC_PLATFORM_NAOMI2:
settings.platform.ram_size = 32 * 1024 * 1024;
settings.platform.vram_size = 16 * 1024 * 1024; // 2x16 MB VRAM, only 16 emulated
settings.platform.aram_size = 8 * 1024 * 1024;
settings.platform.bios_size = 2 * 1024 * 1024;
settings.platform.flash_size = 32 * 1024; // battery-backed ram
break;
case DC_PLATFORM_ATOMISWAVE:
settings.platform.ram_size = 16 * 1024 * 1024;
settings.platform.vram_size = 8 * 1024 * 1024;
@@ -392,7 +406,7 @@ void Emulator::init()
pvr::init();
libAICA_Init();
libARM_Init();
aicaarm::init();
mem_Init();
reios_init();
@@ -446,11 +460,14 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
mem_map_default();
config::Settings::instance().reset();
dc_reset(true);
config::Settings::instance().load(false);
dc_reset(true);
memset(&settings.network.md5, 0, sizeof(settings.network.md5));
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isNaomi2() && config::RendererType == RenderType::DirectX9)
throw FlycastException("DirectX 9 doesn't support Naomi 2 games. Select a different graphics API");
if (settings.platform.isConsole())
{
if (settings.content.path.empty())
{
@@ -491,7 +508,7 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
}
}
}
else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE)
else if (settings.platform.isArcade())
{
LoadRomFiles();
naomi_cart_LoadRom(path, progress);
@@ -499,7 +516,11 @@ void Emulator::loadGame(const char *path, LoadProgress *progress)
// Reload the BIOS in case a game-specific region is set
naomi_cart_LoadBios(path);
}
mcfg_DestroyDevices();
mcfg_CreateDevices();
if (settings.platform.isNaomi())
// Must be done after the maple devices are created and EEPROM is accessible
naomi_cart_ConfigureEEPROM();
cheatManager.reset(settings.content.gameId);
if (cheatManager.isWidescreen())
{
@@ -573,7 +594,6 @@ void Emulator::term()
sh4_cpu.Term();
custom_texture.Terminate(); // lr: avoid deadlock on exit (win32)
reios_term();
libARM_Term();
libAICA_Term();
pvr::term();
mem_Term();
@@ -617,7 +637,7 @@ void Emulator::requestReset()
void loadGameSpecificSettings()
{
char *reios_id;
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isConsole())
{
static char _disk_id[sizeof(ip_meta.product_number) + 1];
@@ -644,6 +664,12 @@ void loadGameSpecificSettings()
// Reload per-game settings
config::Settings::instance().load(true);
if (config::ForceWindowsCE)
{
config::ExtraDepthScale.override(0.1f);
config::FullMMU.override(true);
}
}
void Emulator::step()
@@ -812,7 +838,7 @@ bool Emulator::render()
void Emulator::vblank()
{
lua::vblank();
EventManager::event(Event::VBlank);
// Time out if a frame hasn't been rendered for 50 ms
if (sh4_sched_now64() - startTime <= 10000000)
return;
+1
View File
@@ -45,6 +45,7 @@ enum class Event {
Resume,
Terminate,
LoadState,
VBlank,
};
class EventManager
+23 -13
View File
@@ -18,6 +18,7 @@ InterruptInfo* MCIRE;
InterruptInfo* SCIEB;
InterruptInfo* SCIPD;
InterruptInfo* SCIRE;
std::deque<u8> midiSendBuffer;
//Interrupts
//arm side
@@ -135,7 +136,7 @@ static void AicaInternalDMA()
// to regs
u32 addr = CommonData->DRGA << 2;
for (u32 i = 0; i < CommonData->DLG; i++, addr += 4)
WriteMem_aica_reg(addr, 0, 4);
WriteMem_aica_reg(addr, (u32)0);
}
}
else
@@ -148,13 +149,13 @@ static void AicaInternalDMA()
{
// reg to wave mem
for (u32 i = 0; i < len; i++, waddr += 4, raddr += 4)
*(u32*)&aica_ram[waddr] = ReadMem_aica_reg(raddr, 4);
*(u32*)&aica_ram[waddr] = ReadMem_aica_reg<u32>(raddr);
}
else
{
// wave mem to regs
for (u32 i = 0; i < len; i++, waddr += 4, raddr += 4)
WriteMem_aica_reg(raddr, *(u32*)&aica_ram[waddr], 4);
WriteMem_aica_reg(raddr, *(u32*)&aica_ram[waddr]);
}
}
CommonData->DEXE = 0;
@@ -165,9 +166,10 @@ static void AicaInternalDMA()
}
//Memory i/o
template<u32 sz>
void WriteAicaReg(u32 reg,u32 data)
template<typename T>
void WriteAicaReg(u32 reg, T data)
{
constexpr size_t sz = sizeof(T);
switch (reg)
{
case SCIPD_addr:
@@ -204,36 +206,44 @@ void WriteAicaReg(u32 reg,u32 data)
break;
case TIMER_A:
WriteMemArr<sz>(aica_reg, reg, data);
WriteMemArr(aica_reg, reg, data);
timers[0].RegisterWrite();
break;
case TIMER_B:
WriteMemArr<sz>(aica_reg, reg, data);
WriteMemArr(aica_reg, reg, data);
timers[1].RegisterWrite();
break;
case TIMER_C:
WriteMemArr<sz>(aica_reg, reg, data);
WriteMemArr(aica_reg, reg, data);
timers[2].RegisterWrite();
break;
// DEXE, DDIR, DLG
case 0x288C:
WriteMemArr<sz>(aica_reg, reg, data);
WriteMemArr(aica_reg, reg, data);
AicaInternalDMA();
break;
default:
WriteMemArr<sz>(aica_reg, reg, data);
WriteMemArr(aica_reg, reg, data);
break;
}
}
template void WriteAicaReg<>(u32 reg, u8 data);
template void WriteAicaReg<>(u32 reg, u16 data);
template void WriteAicaReg<>(u32 reg, u32 data);
template void WriteAicaReg<1>(u32 reg,u32 data);
template void WriteAicaReg<2>(u32 reg,u32 data);
void aica_midiSend(u8 data)
{
midiSendBuffer.push_back(data);
SCIPD->MIDI_IN = 1;
update_arm_interrupts();
MCIPD->MIDI_IN = 1;
UpdateSh4Ints();
}
//misc :p
s32 libAICA_Init()
+4 -2
View File
@@ -1,5 +1,6 @@
#pragma once
#include "types.h"
#include <deque>
#define SCIEB_addr 0x289C
#define SCIPD_addr (0x289C+4)
@@ -299,12 +300,13 @@ extern InterruptInfo* MCIRE;
extern InterruptInfo* SCIEB;
extern InterruptInfo* SCIPD;
extern InterruptInfo* SCIRE;
extern std::deque<u8> midiSendBuffer;
extern CommonData_struct* CommonData;
extern DSPData_struct* DSPData;
template<u32 sz>
void WriteAicaReg(u32 reg,u32 data);
template<typename T>
void WriteAicaReg(u32 reg, T data);
class AicaTimer
{
+37 -15
View File
@@ -45,23 +45,28 @@ u32 GetRTC_now()
return (20 * 365 + 5) * 24 * 60 * 60 + rawtime + time_offset;
}
u32 ReadMem_aica_rtc(u32 addr, u32 sz)
template<typename T>
T ReadMem_aica_rtc(u32 addr)
{
switch (addr & 0xFF)
{
case 0:
return RealTimeClock >> 16;
return (T)(RealTimeClock >> 16);
case 4:
return RealTimeClock & 0xFFFF;
return (T)(RealTimeClock & 0xFFFF);
case 8:
return 0;
}
WARN_LOG(AICA, "ReadMem_aica_rtc: invalid address %x sz %d", addr, sz);
WARN_LOG(AICA, "ReadMem_aica_rtc: invalid address %x sz %d", addr, (int)sizeof(T));
return 0;
}
template u8 ReadMem_aica_rtc<>(u32 addr);
template u16 ReadMem_aica_rtc<>(u32 addr);
template u32 ReadMem_aica_rtc<>(u32 addr);
void WriteMem_aica_rtc(u32 addr, u32 data, u32 sz)
template<typename T>
void WriteMem_aica_rtc(u32 addr, T data)
{
switch (addr & 0xFF)
{
@@ -86,31 +91,41 @@ void WriteMem_aica_rtc(u32 addr, u32 data, u32 sz)
break;
default:
WARN_LOG(AICA, "WriteMem_aica_rtc: invalid address %x sz %d data %x", addr, sz, data);
WARN_LOG(AICA, "WriteMem_aica_rtc: invalid address %x sz %d data %x", addr, (int)sizeof(T), data);
break;
}
}
template void WriteMem_aica_rtc<>(u32 addr, u8 data);
template void WriteMem_aica_rtc<>(u32 addr, u16 data);
template void WriteMem_aica_rtc<>(u32 addr, u32 data);
u32 ReadMem_aica_reg(u32 addr, u32 sz)
template<typename T>
T ReadMem_aica_reg(u32 addr)
{
addr &= 0x7FFF;
if (sz == 1)
if (sizeof(T) == 1)
{
switch (addr)
{
case 0x2C00:
return ARMRST;
return (T)ARMRST;
case 0x2C01:
return VREG;
return (T)VREG;
default:
break;
}
}
else if (addr == 0x2C00)
return (VREG << 8) | ARMRST;
return (T)((VREG << 8) | ARMRST);
return libAICA_ReadReg(addr, sz);
if (sizeof(T) == 4)
return aicaReadReg<u16>(addr);
else
return aicaReadReg<T>(addr);
}
template u8 ReadMem_aica_reg<>(u32 addr);
template u16 ReadMem_aica_reg<>(u32 addr);
template u32 ReadMem_aica_reg<>(u32 addr);
static void ArmSetRST()
{
@@ -118,11 +133,12 @@ static void ArmSetRST()
aicaarm::enable(ARMRST == 0);
}
void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
template<typename T>
void WriteMem_aica_reg(u32 addr, T data)
{
addr &= 0x7FFF;
if (sz == 1)
if (sizeof(T) == 1)
{
switch (addr)
{
@@ -147,8 +163,14 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
ArmSetRST();
return;
}
libAICA_WriteReg(addr, data, sz);
if (sizeof(T) == 4)
aicaWriteReg(addr, (u16)data);
else
aicaWriteReg(addr, data);
}
template void WriteMem_aica_reg<>(u32 addr, u8 data);
template void WriteMem_aica_reg<>(u32 addr, u16 data);
template void WriteMem_aica_reg<>(u32 addr, u32 data);
static int DreamcastSecond(int tag, int c, int j)
{
+6 -4
View File
@@ -5,14 +5,16 @@
extern u32 VREG;
extern VArray2 aica_ram;
u32 GetRTC_now();
u32 ReadMem_aica_rtc(u32 addr,u32 sz);
void WriteMem_aica_rtc(u32 addr,u32 data,u32 sz);
u32 ReadMem_aica_reg(u32 addr,u32 sz);
void WriteMem_aica_reg(u32 addr,u32 data,u32 sz);
template<typename T> T ReadMem_aica_rtc(u32 addr);
template<typename T> void WriteMem_aica_rtc(u32 addr, T data);
template<typename T> T ReadMem_aica_reg(u32 addr);
template<typename T> void WriteMem_aica_reg(u32 addr, T data);
void aica_Init();
void aica_Reset(bool hard);
void aica_Term();
void aica_setMidiReceiver(void (*handler)(u8 data));
void aica_midiSend(u8 data);
void aica_sb_Init();
void aica_sb_Reset(bool hard);
+54 -57
View File
@@ -3,22 +3,26 @@
#include "aica_if.h"
#include "dsp.h"
#include "sgc_if.h"
#include "hw/hwreg.h"
alignas(4) u8 aica_reg[0x8000];
static void (*midiReceiver)(u8 data);
//Aica read/write (both sh4 & arm)
//00000000~007FFFFF @DRAM_AREA*
//00800000~008027FF @CHANNEL_DATA
//00802800~00802FFF @COMMON_DATA
//00803000~00807FFF @DSP_DATA
template<u32 sz>
u32 ReadReg(u32 addr)
template<typename T>
T aicaReadReg(u32 addr)
{
addr &= 0x7FFF;
if (addr >= 0x2800 && addr < 0x2818)
{
if (sz == 1)
ReadCommonReg(addr, true);
else
ReadCommonReg(addr, false);
ReadCommonReg(addr, sizeof(T) == 1);
}
else if (addr >= 0x4000 && addr < 0x4580)
{
@@ -47,7 +51,7 @@ u32 ReadReg(u32 addr)
else
v &= 0xf;
}
if (sz == 1)
if (sizeof(T) == 1)
{
if (addr & 1)
v >>= 8;
@@ -56,42 +60,55 @@ u32 ReadReg(u32 addr)
}
return v;
}
return ReadMemArr<sz>(aica_reg, addr);
return ReadMemArr<T>(aica_reg, addr);
}
template u8 aicaReadReg<u8>(u32 addr);
template u16 aicaReadReg<u16>(u32 addr);
template u32 aicaReadReg<u32>(u32 addr);
static void writeCommonReg8(u32 reg, u8 data)
{
WriteMemArr(aica_reg, reg, data);
if (reg == 0x2804 || reg == 0x2805)
{
using namespace dsp;
state.RBL = (8192 << CommonData->RBL) - 1;
state.RBP = (CommonData->RBP * 2048) & ARAM_MASK;
state.dirty = true;
}
else if (reg == 0x280c) { // MOBUF
if (midiReceiver != nullptr)
midiReceiver(data);
}
}
template<u32 sz>
void WriteReg(u32 addr,u32 data)
template<typename T>
void aicaWriteReg(u32 addr, T data)
{
constexpr size_t sz = sizeof(T);
addr &= 0x7FFF;
if (addr < 0x2000)
{
//Channel data
u32 chan = addr >> 7;
u32 reg = addr & 0x7F;
WriteMemArr<sz>(aica_reg, addr, data);
WriteMemArr(aica_reg, addr, data);
WriteChannelReg(chan, reg, sz);
return;
}
if (addr < 0x2800)
{
if (sz == 1)
WriteMemArr<1>(aica_reg, addr, data);
else
WriteMemArr<2>(aica_reg, addr, data);
WriteMemArr(aica_reg, addr, data);
return;
}
if (addr < 0x2818)
{
if (sz == 1)
{
WriteCommonReg8(addr, data);
}
else
{
WriteCommonReg8(addr, data & 0xFF);
WriteCommonReg8(addr + 1, data >> 8);
}
writeCommonReg8(addr, data & 0xFF);
if (sz == 2)
writeCommonReg8(addr + 1, data >> 8);
return;
}
@@ -128,7 +145,7 @@ void WriteReg(u32 addr,u32 data)
v = (v & ~0xff) | (data & 0xff);
// else ignored
}
DEBUG_LOG(AICA, "DSP TEMP/MEMS register write<%d> @ %x = %d", sz, addr, v);
DEBUG_LOG(AICA, "DSP TEMP/MEMS register write<%d> @ %x = %d", (int)sz, addr, v);
}
// DSP MIXS
else
@@ -154,55 +171,35 @@ void WriteReg(u32 addr,u32 data)
v = (v & ~0xf) | (data & 0xf);
// else ignored
}
DEBUG_LOG(AICA, "DSP MIXS register write<%d> @ %x = %d", sz, addr, v);
DEBUG_LOG(AICA, "DSP MIXS register write<%d> @ %x = %d", (int)sz, addr, v);
}
return;
}
if (sz == 1)
{
WriteMemArr<1>(aica_reg, addr, data);
dsp::writeProg(addr);
}
else
{
WriteMemArr<2>(aica_reg, addr, data);
dsp::writeProg(addr);
WriteMemArr(aica_reg, addr, data);
dsp::writeProg(addr);
if (sz == 2)
dsp::writeProg(addr + 1);
}
return;
}
if (sz == 1)
WriteAicaReg<1>(addr, data);
else
WriteAicaReg<2>(addr, data);
}
//Aica reads (both sh4&arm)
u32 libAICA_ReadReg(u32 addr, u32 size)
{
if (size == 1)
return ReadReg<1>(addr & 0x7FFF);
else
return ReadReg<2>(addr & 0x7FFF);
}
void libAICA_WriteReg(u32 addr, u32 data, u32 size)
{
if (size == 1)
WriteReg<1>(addr & 0x7FFF, data);
else
WriteReg<2>(addr & 0x7FFF, data);
WriteAicaReg(addr, data);
}
template void aicaWriteReg<>(u32 addr, u8 data);
template void aicaWriteReg<>(u32 addr, u16 data);
template void aicaWriteReg<>(u32 addr, u32 data);
void init_mem()
{
memset(aica_reg, 0, sizeof(aica_reg));
aica_ram.data[ARAM_SIZE - 1] = 1;
aica_ram.Zero();
midiReceiver = nullptr;
}
void term_mem()
{
}
void aica_setMidiReceiver(void (*handler)(u8 data)) {
midiReceiver = handler;
}
+2 -2
View File
@@ -1,8 +1,8 @@
#pragma once
#include "types.h"
u32 libAICA_ReadReg(u32 addr,u32 size);
void libAICA_WriteReg(u32 addr,u32 data,u32 size);
template<typename T> T aicaReadReg(u32 addr);
template<typename T> void aicaWriteReg(u32 addr, T data);
void init_mem();
void term_mem();
+69 -45
View File
@@ -27,6 +27,7 @@
#include "hw/gdrom/gdrom_if.h"
#include "cfg/option.h"
#include "serialize.h"
#include "hw/hwreg.h"
#include <algorithm>
#include <cmath>
@@ -779,7 +780,6 @@ struct ChannelEx
FEG.ReleaseRate = FEG_SPS[EG_EffRate(base_rate, ccd->FRR)];
}
//WHEE :D!
void RegWrite(u32 offset, int size)
{
switch(offset)
@@ -1024,7 +1024,7 @@ void StreamStep(ChannelEx* ch)
else
{
CA = ch->loop.LSA;
key_printf("[%d]LPCTL : Looping LSA %x LEA %x", ch->ChannelNumber, ch->loop.LSA, ch->loop.LEA);
key_printf("[%d]LPCTL : Looping LSA %x LEA %x AEG %x", ch->ChannelNumber, ch->loop.LSA, ch->loop.LEA, ch->AEG.GetValue());
}
}
@@ -1040,52 +1040,60 @@ void StreamStep(ChannelEx* ch)
}
template<s32 ALFOWS>
enum class LFOType
{
Sawtooth,
Square,
Triangle,
Random
};
template<LFOType Type>
void CalcAlfo(ChannelEx* ch)
{
u32 rv;
switch(ALFOWS)
switch(Type)
{
case 0: // Sawtooth
case LFOType::Sawtooth:
rv=ch->lfo.state;
break;
case 1: // Square
case LFOType::Square:
rv=ch->lfo.state&0x80?255:0;
break;
case 2: // Triangle
case LFOType::Triangle:
rv=(ch->lfo.state&0x7f)^(ch->lfo.state&0x80 ? 0x7F:0);
rv<<=1;
break;
case 3:// Random ! .. not :p
case LFOType::Random: // ... not so much
rv=(ch->lfo.state>>3)^(ch->lfo.state<<3)^(ch->lfo.state&0xE3);
break;
}
ch->lfo.alfo=rv>>ch->lfo.alfo_shft;
}
template<s32 PLFOWS>
template<LFOType Type>
void CalcPlfo(ChannelEx* ch)
{
u32 rv;
switch(PLFOWS)
switch(Type)
{
case 0: // sawtooth
case LFOType::Sawtooth:
rv = ch->lfo.state;
break;
case 1: // square
case LFOType::Square:
rv = ch->lfo.state & 0x80 ? 0xff : 0;
break;
case 2: // triangle
case LFOType::Triangle:
rv = (ch->lfo.state & 0x7f) ^ (ch->lfo.state & 0x80 ? 0x7F : 0);
rv <<= 1;
break;
case 3:// random ! .. not :p
case LFOType::Random:
rv = (ch->lfo.state >> 3) ^ (ch->lfo.state << 3) ^ (ch->lfo.state & 0xE3);
break;
}
@@ -1220,25 +1228,25 @@ static void staticinitialise()
STREAM_INITAL_STEP_LUT[3]=&StepDecodeSampleInitial<3>;
STREAM_INITAL_STEP_LUT[4]=&StepDecodeSampleInitial<-1>;
AEG_STEP_LUT[0]=&AegStep<0>;
AEG_STEP_LUT[1]=&AegStep<1>;
AEG_STEP_LUT[2]=&AegStep<2>;
AEG_STEP_LUT[3]=&AegStep<3>;
AEG_STEP_LUT[EG_Attack] = &AegStep<EG_Attack>;
AEG_STEP_LUT[EG_Decay1] = &AegStep<EG_Decay1>;
AEG_STEP_LUT[EG_Decay2] = &AegStep<EG_Decay2>;
AEG_STEP_LUT[EG_Release] = &AegStep<EG_Release>;
FEG_STEP_LUT[0]=&FegStep<0>;
FEG_STEP_LUT[1]=&FegStep<1>;
FEG_STEP_LUT[2]=&FegStep<2>;
FEG_STEP_LUT[3]=&FegStep<3>;
FEG_STEP_LUT[EG_Attack] = &FegStep<EG_Attack>;
FEG_STEP_LUT[EG_Decay1] = &FegStep<EG_Decay1>;
FEG_STEP_LUT[EG_Decay2] = &FegStep<EG_Decay2>;
FEG_STEP_LUT[EG_Release] = &FegStep<EG_Release>;
ALFOWS_CALC[0]=&CalcAlfo<0>;
ALFOWS_CALC[1]=&CalcAlfo<1>;
ALFOWS_CALC[2]=&CalcAlfo<2>;
ALFOWS_CALC[3]=&CalcAlfo<3>;
ALFOWS_CALC[(int)LFOType::Sawtooth] = &CalcAlfo<LFOType::Sawtooth>;
ALFOWS_CALC[(int)LFOType::Square] = &CalcAlfo<LFOType::Square>;
ALFOWS_CALC[(int)LFOType::Triangle] = &CalcAlfo<LFOType::Triangle>;
ALFOWS_CALC[(int)LFOType::Random] = &CalcAlfo<LFOType::Random>;
PLFOWS_CALC[0]=&CalcPlfo<0>;
PLFOWS_CALC[1]=&CalcPlfo<1>;
PLFOWS_CALC[2]=&CalcPlfo<2>;
PLFOWS_CALC[3]=&CalcPlfo<3>;
PLFOWS_CALC[(int)LFOType::Sawtooth] = &CalcPlfo<LFOType::Sawtooth>;
PLFOWS_CALC[(int)LFOType::Square] = &CalcPlfo<LFOType::Square>;
PLFOWS_CALC[(int)LFOType::Triangle] = &CalcPlfo<LFOType::Triangle>;
PLFOWS_CALC[(int)LFOType::Random] = &CalcPlfo<LFOType::Random>;
}
ChannelEx ChannelEx::Chans[64];
@@ -1330,10 +1338,23 @@ void ReadCommonReg(u32 reg,bool byte)
{
case 0x2808:
case 0x2809:
CommonData->MIEMP = 1;
CommonData->MOEMP = 1;
if (!midiSendBuffer.empty())
{
if (!byte || reg == 0x2808)
{
CommonData->MIBUF = midiSendBuffer.front();
midiSendBuffer.pop_front();
}
CommonData->MIEMP = 0;
CommonData->MIFUL = 1;
}
else
{
CommonData->MIEMP = 1;
CommonData->MIFUL = 0;
}
CommonData->MIOVF = 0;
CommonData->MIFUL = 0;
CommonData->MOEMP = 1;
CommonData->MOFUL = 0;
break;
case 0x2810: // EG, SGC, LP
@@ -1365,18 +1386,6 @@ void ReadCommonReg(u32 reg,bool byte)
}
}
void WriteCommonReg8(u32 reg,u32 data)
{
WriteMemArr<1>(aica_reg, reg, data);
if (reg == 0x2804 || reg == 0x2805)
{
using namespace dsp;
state.RBL = (8192 << CommonData->RBL) - 1;
state.RBP = (CommonData->RBP * 2048) & ARAM_MASK;
state.dirty = true;
}
}
void vmuBeep(int on, int period)
{
if (on == 0 || period == 0 || on < period)
@@ -1631,6 +1640,9 @@ void channel_serialize(Serializer& ser)
ser << beepCounter;
ser << cdda_sector;
ser << cdda_index;
ser << (u32)midiSendBuffer.size();
for (u8 b : midiSendBuffer)
ser << b;
}
void channel_deserialize(Deserializer& deser)
@@ -1765,4 +1777,16 @@ void channel_deserialize(Deserializer& deser)
deser.skip(4 * 64); // mxlr
deser.skip(4); // samples_gen
}
midiSendBuffer.clear();
if (deser.version() >= Deserializer::V28)
{
u32 size;
deser >> size;
for (u32 i = 0; i < size; i++)
{
u8 b;
deser >> b;
midiSendBuffer.push_back(b);
}
}
}
+1 -2
View File
@@ -52,8 +52,7 @@ struct DSP_OUT_VOL_REG
typedef s32 SampleType;
void ReadCommonReg(u32 reg,bool byte);
void WriteCommonReg8(u32 reg,u32 data);
void ReadCommonReg(u32 reg, bool byte);
void channel_serialize(Serializer& ctx);
void channel_deserialize(Deserializer& ctx);
void vmuBeep(int on, int period);
-2
View File
@@ -15,9 +15,7 @@
#define reg arm_Reg
#define armNextPC reg[R15_ARM_NEXT].I
#define CPUUpdateTicksAccesint(a) 1
#define CPUUpdateTicksAccessSeq32(a) 1
#define CPUUpdateTicksAccesshort(a) 1
#define CPUUpdateTicksAccess32(a) 1
#define CPUUpdateTicksAccess16(a) 1
+2 -1
View File
@@ -98,7 +98,8 @@ typedef union
alignas(8) extern reg_pair arm_Reg[RN_ARM_REG_COUNT];
#define ARM_CYCLES_PER_SAMPLE 256
// AICA ARM cpu clock: 22.5792 MHz
#define ARM_CYCLES_PER_SAMPLE 512
extern int arm7ClockTicks;
void CPUFiq();
+13 -2
View File
@@ -145,6 +145,7 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
//NV condition means VFP on newer cores, let interpreter handle it...
op.op_type = ArmOp::FALLBACK;
op.arg[0] = ArmOp::Operand(opcode);
op.cycles = 0;
return op;
}
if (op.condition != ArmOp::AL)
@@ -237,6 +238,7 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
else
{
op.arg[argidx].shift_reg = ArmOp::Register((Arm7Reg)bits.shift_reg);
op.cycles++;
}
// Compute pc-relative addresses
if (op.arg[argidx].getReg().armreg == RN_PC)
@@ -274,6 +276,7 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
op.op_type = ArmOp::B;
op.flags |= ArmOp::OP_SETS_PC;
op.rd = ArmOp::Operand();
op.cycles += 3;
return op;
}
if (op.condition != ArmOp::AL || (op.flags & ArmOp::OP_SETS_FLAGS))
@@ -287,7 +290,10 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
op.cycles = 0;
}
else
{
op.rd.getReg().armreg = R15_ARM_NEXT;
op.cycles++;
}
op.flags |= ArmOp::OP_SETS_PC;
}
if (op.op_type == ArmOp::ADC || op.op_type == ArmOp::SBC || op.op_type == ArmOp::RSC)
@@ -317,6 +323,7 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
return op;
}
op.rd.setReg(R15_ARM_NEXT);
op.cycles++;
}
op.cycles += 4;
}
@@ -417,7 +424,9 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
arm_printf("ARM: MEM TFX R %08X -> %08X", opcode, newbits.full);
return decodeArmOp(newbits.full, arm_pc);
op = decodeArmOp(newbits.full, arm_pc);
op.cycles += 4;
return op;
}
//STM common case
else
@@ -448,7 +457,9 @@ static ArmOp decodeArmOp(u32 opcode, u32 arm_pc)
arm_printf("ARM: MEM TFX W %08X -> %08X", opcode, newbits.full);
return decodeArmOp(newbits.full, arm_pc);
op = decodeArmOp(newbits.full, arm_pc);
op.cycles += 4;
return op;
}
}
op.op_type = ArmOp::FALLBACK;
+23 -17
View File
@@ -41,19 +41,22 @@ void e68k_AcceptInterrupt()
}
//Reg reads from arm side ..
template <u32 sz,class T>
template <typename T>
T arm_ReadReg(u32 addr)
{
addr&=0x7FFF;
if (addr==REG_L)
return e68k_reg_L;
else if(addr==REG_M)
return e68k_reg_M; //shouldn't really happen
addr &= 0x7FFF;
if (addr == REG_L)
return (T)e68k_reg_L;
else if (addr == REG_M)
return (T)e68k_reg_M; //shouldn't really happen
else if (sizeof(T) == 4)
return aicaReadReg<u16>(addr);
else
return libAICA_ReadReg(addr,sz);
}
template <u32 sz,class T>
void arm_WriteReg(u32 addr,T data)
return aicaReadReg<T>(addr);
}
template <typename T>
void arm_WriteReg(u32 addr, T data)
{
addr &= 0x7FFF;
if (addr == REG_L)
@@ -68,7 +71,10 @@ void arm_WriteReg(u32 addr,T data)
}
else
{
return libAICA_WriteReg(addr, data, sz);
if (sizeof(T) == 4)
aicaWriteReg(addr, (u16)data);
else
aicaWriteReg(addr, data);
}
}
@@ -77,10 +83,10 @@ void arm_WriteReg(u32 addr,T data)
//00802800~00802FFF @COMMON_DATA
//00803000~00807FFF @DSP_DATA
template u8 arm_ReadReg<1,u8>(u32 adr);
template u16 arm_ReadReg<2,u16>(u32 adr);
template u32 arm_ReadReg<4,u32>(u32 adr);
template u8 arm_ReadReg<u8>(u32 adr);
template u16 arm_ReadReg<u16>(u32 adr);
template u32 arm_ReadReg<u32>(u32 adr);
template void arm_WriteReg<1>(u32 adr,u8 data);
template void arm_WriteReg<2>(u32 adr,u16 data);
template void arm_WriteReg<4>(u32 adr,u32 data);
template void arm_WriteReg<>(u32 adr,u8 data);
template void arm_WriteReg<>(u32 adr,u16 data);
template void arm_WriteReg<>(u32 adr,u32 data);
+22 -24
View File
@@ -2,54 +2,52 @@
#include "types.h"
#include "hw/aica/aica_if.h"
template <u32 sz,class T>
T arm_ReadReg(u32 addr);
template <u32 sz,class T>
void arm_WriteReg(u32 addr,T data);
template <typename T> T arm_ReadReg(u32 addr);
template <typename T> void arm_WriteReg(u32 addr, T data);
template<int sz,typename T>
template<typename T>
static inline T DYNACALL ReadMemArm(u32 addr)
{
addr&=0x00FFFFFF;
if (addr<0x800000)
addr &= 0x00FFFFFF;
if (addr < 0x800000)
{
T rv=*(T*)&aica_ram[addr&(ARAM_MASK-(sz-1))];
T rv = *(T *)&aica_ram[addr & (ARAM_MASK - (sizeof(T) - 1))];
if (unlikely(sz==4 && addr&3))
if (unlikely(sizeof(T) == 4 && (addr & 3) != 0))
{
u32 sf=(addr&3)*8;
return (rv>>sf) | (rv<<(32-sf));
u32 sf = (addr & 3) * 8;
return (rv >> sf) | (rv << (32 - sf));
}
else
return rv;
}
else
{
return arm_ReadReg<sz,T>(addr);
return arm_ReadReg<T>(addr);
}
}
template<int sz,typename T>
static inline void DYNACALL WriteMemArm(u32 addr,T data)
template<typename T>
static inline void DYNACALL WriteMemArm(u32 addr, T data)
{
addr&=0x00FFFFFF;
if (addr<0x800000)
addr &= 0x00FFFFFF;
if (addr < 0x800000)
{
*(T*)&aica_ram[addr&(ARAM_MASK-(sz-1))]=data;
*(T *)&aica_ram[addr & (ARAM_MASK - (sizeof(T) - 1))] = data;
}
else
{
arm_WriteReg<sz,T>(addr,data);
arm_WriteReg(addr, data);
}
}
#define arm_ReadMem8 ReadMemArm<1,u8>
#define arm_ReadMem16 ReadMemArm<2,u16>
#define arm_ReadMem32 ReadMemArm<4,u32>
#define arm_ReadMem8 ReadMemArm<u8>
#define arm_ReadMem16 ReadMemArm<u16>
#define arm_ReadMem32 ReadMemArm<u32>
#define arm_WriteMem8 WriteMemArm<1,u8>
#define arm_WriteMem16 WriteMemArm<2,u16>
#define arm_WriteMem32 WriteMemArm<4,u32>
#define arm_WriteMem8 WriteMemArm<u8>
#define arm_WriteMem16 WriteMemArm<u16>
#define arm_WriteMem32 WriteMemArm<u32>
extern bool aica_interr;
extern u32 aica_reg_L;
-25
View File
@@ -1,25 +0,0 @@
// nullAICA.cpp : Defines the entry point for the DLL application.
//
#include "arm7.h"
//called when plugin is used by emu (you should do first time init here)
s32 libARM_Init()
{
aicaarm::init();
return 0;
}
//called when plugin is unloaded by emu, only if dcInit is called (eg, not called to enumerate plugins)
void libARM_Term()
{
//arm7_Term ?
}
//It's supposed to reset anything
void libARM_Reset(bool hard)
{
aicaarm::reset();
aicaarm::enable(false);
}
+2 -1
View File
@@ -152,7 +152,8 @@ struct flash_syscfg_block {
// last set time (seconds since 1/1/1950 00:00)
u16 time_lo;
u16 time_hi;
u8 unknown1;
// in 15 mins increment, from -48 (West) to +52 (East), unused
int8_t time_zone;
u8 lang;
u8 mono;
u8 autostart;
+90 -1
View File
@@ -456,6 +456,69 @@ void gd_process_ata_cmd()
};
}
static u16 ccitt_crc(void *data, int len)
{
static constexpr u16 crctable[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
};
u16 crc = 0;
u8 *p = (u8 *)data;
while (len-- > 0)
crc = ((crc & 0xff) << 8) ^ crctable[((crc >> 8) & 0xff) ^ *p++];
return ~crc;
}
static int bin2bcd(int v)
{
return (v % 10) | ((v / 10) << 4);
}
static void encodeSubcode(u8 *buffer, u8 data)
{
buffer[0] = (data & 0x80) ? 0x40 : 0;
buffer[1] = (data & 0x40) ? 0x40 : 0;
buffer[2] = (data & 0x20) ? 0x40 : 0;
buffer[3] = (data & 0x10) ? 0x40 : 0;
buffer[4] = (data & 0x08) ? 0x40 : 0;
buffer[5] = (data & 0x04) ? 0x40 : 0;
buffer[6] = (data & 0x02) ? 0x40 : 0;
buffer[7] = (data & 0x01) ? 0x40 : 0;
}
u32 gd_get_subcode(u32 format, u32 fad, u8 *subc_info)
{
subc_info[0] = 0;
@@ -481,7 +544,33 @@ u32 gd_get_subcode(u32 format, u32 fad, u8 *subc_info)
case 0: // Raw subcode
subc_info[2] = 0;
subc_info[3] = 100;
libGDR_ReadSubChannel(subc_info + 4, 100 - 4);
// usually not available so let's fake it (Q data only)
//libGDR_ReadSubChannel(subc_info + 4, 100 - 4);
{
u32 curFad = cdda.status == cdda_t::Playing || cdda.status == cdda_t::Paused ? cdda.CurrAddr.FAD : fad;
u32 elapsed;
u32 tracknum = libGDR_GetTrackNumber(curFad, elapsed);
u8 Qch[12];
Qch[0] = (SecNumber.DiscFormat == 0 ? 0 : 0x40) | 1;
Qch[1] = bin2bcd(tracknum);
Qch[2] = bin2bcd(1); // index
Qch[3] = bin2bcd(elapsed / 60 / 75); // min
Qch[4] = bin2bcd((elapsed / 75) % 60); // sec
Qch[5] = bin2bcd(elapsed % 75); // frame
Qch[6] = 0;
Qch[7] = bin2bcd(curFad / 60 / 75); // toc min
Qch[8] = bin2bcd((curFad / 75) % 60); // toc sec
Qch[9] = bin2bcd(curFad % 75); // toc frame
u16 crc = ccitt_crc(Qch, 10);
Qch[10] = crc >> 8;
Qch[11] = crc;
u8 *p = &subc_info[4];
for (u8 q : Qch)
{
encodeSubcode(p, q);
p += 8;
}
}
break;
case 1: // Q data only
+151 -48
View File
@@ -10,29 +10,32 @@
//asic_RLXXPending: Update the intc flags for pending interrupts
static void asic_RL6Pending()
{
bool t1=(SB_ISTNRM & SB_IML6NRM)!=0;
bool t2=(SB_ISTERR & SB_IML6ERR)!=0;
bool t3=(SB_ISTEXT & SB_IML6EXT)!=0;
bool t1 = (SB_ISTNRM & SB_IML6NRM) != 0;
bool t2 = (SB_ISTERR & SB_IML6ERR) != 0;
bool t3 = (SB_ISTEXT & SB_IML6EXT) != 0;
bool t4 = (SB_ISTNRM1 & SB_IML6NRM) != 0;
InterruptPend(sh4_IRL_9,t1|t2|t3);
InterruptPend(sh4_IRL_9,t1 | t2 | t3 | t4);
}
static void asic_RL4Pending()
{
bool t1=(SB_ISTNRM & SB_IML4NRM)!=0;
bool t2=(SB_ISTERR & SB_IML4ERR)!=0;
bool t3=(SB_ISTEXT & SB_IML4EXT)!=0;
bool t1 = (SB_ISTNRM & SB_IML4NRM) != 0;
bool t2 = (SB_ISTERR & SB_IML4ERR) != 0;
bool t3 = (SB_ISTEXT & SB_IML4EXT) != 0;
bool t4 = (SB_ISTNRM1 & SB_IML4NRM) != 0;
InterruptPend(sh4_IRL_11,t1|t2|t3);
InterruptPend(sh4_IRL_11, t1 | t2 | t3 | t4);
}
static void asic_RL2Pending()
{
bool t1=(SB_ISTNRM & SB_IML2NRM)!=0;
bool t2=(SB_ISTERR & SB_IML2ERR)!=0;
bool t3=(SB_ISTEXT & SB_IML2EXT)!=0;
bool t1 = (SB_ISTNRM & SB_IML2NRM) != 0;
bool t2 = (SB_ISTERR & SB_IML2ERR) != 0;
bool t3 = (SB_ISTEXT & SB_IML2EXT) != 0;
bool t4 = (SB_ISTNRM1 & SB_IML2NRM) != 0;
InterruptPend(sh4_IRL_13,t1|t2|t3);
InterruptPend(sh4_IRL_13, t1 | t2 | t3 | t4);
}
void asic_RaiseInterrupt(HollyInterruptID inter)
@@ -56,13 +59,36 @@ void asic_RaiseInterrupt(HollyInterruptID inter)
asic_RL6Pending();
}
void asic_RaiseInterruptBothCLX(HollyInterruptID inter)
{
u8 type = inter >> 8;
u32 mask = 1 << (u8)inter;
switch(type)
{
case 0:
SB_ISTNRM1 |= mask;
SB_ISTNRM |= mask;
break;
case 1:
SB_ISTEXT |= mask;
break;
case 2:
SB_ISTERR |= mask;
break;
}
asic_RL2Pending();
asic_RL4Pending();
asic_RL6Pending();
}
template<bool Naomi2>
static u32 Read_SB_ISTNRM(u32 addr)
{
/* Note that the two highest bits indicate
* the OR'ed result of all the bits in
* SB_ISTEXT and SB_ISTERR, respectively,
* and writes to these two bits are ignored. */
u32 tmp = SB_ISTNRM & 0x3FFFFFFF;
u32 tmp = (Naomi2 && (addr & 0x02000000) != 0 ? SB_ISTNRM1 : SB_ISTNRM) & 0x3FFFFFFF;
if (SB_ISTEXT)
tmp|=0x40000000;
@@ -73,10 +99,14 @@ static u32 Read_SB_ISTNRM(u32 addr)
return tmp;
}
template<bool Naomi2>
static void Write_SB_ISTNRM(u32 addr, u32 data)
{
/* writing a 1 clears the interrupt */
SB_ISTNRM &= ~data;
if (Naomi2 && (addr & 0x02000000) != 0)
SB_ISTNRM1 &= ~data;
else
SB_ISTNRM &= ~data;
asic_RL2Pending();
asic_RL4Pending();
@@ -118,91 +148,107 @@ static void Write_SB_ISTERR(u32 addr, u32 data)
asic_RL6Pending();
}
template<bool Naomi2>
static void Write_SB_IML6NRM(u32 addr, u32 data)
{
SB_IML6NRM=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML6NRM = data;
asic_RL6Pending();
}
template<bool Naomi2>
static void Write_SB_IML4NRM(u32 addr, u32 data)
{
SB_IML4NRM=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML4NRM = data;
asic_RL4Pending();
}
template<bool Naomi2>
static void Write_SB_IML2NRM(u32 addr, u32 data)
{
SB_IML2NRM=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML2NRM = data;
asic_RL2Pending();
}
template<bool Naomi2>
static void Write_SB_IML6EXT(u32 addr, u32 data)
{
SB_IML6EXT=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML6EXT = data;
asic_RL6Pending();
}
template<bool Naomi2>
static void Write_SB_IML4EXT(u32 addr, u32 data)
{
SB_IML4EXT=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML4EXT = data;
asic_RL4Pending();
}
template<bool Naomi2>
static void Write_SB_IML2EXT(u32 addr, u32 data)
{
SB_IML2EXT=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML2EXT = data;
asic_RL2Pending();
}
template<bool Naomi2>
static void Write_SB_IML6ERR(u32 addr, u32 data)
{
SB_IML6ERR=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML6ERR = data;
asic_RL6Pending();
}
template<bool Naomi2>
static void Write_SB_IML4ERR(u32 addr, u32 data)
{
SB_IML4ERR=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML4ERR = data;
asic_RL4Pending();
}
template<bool Naomi2>
static void Write_SB_IML2ERR(u32 addr, u32 data)
{
SB_IML2ERR=data;
if (Naomi2 && (addr & 0x2000000) != 0)
// Ignore CLXB settings
return;
SB_IML2ERR = data;
asic_RL2Pending();
}
void asic_reg_Init()
{
sb_rio_register(SB_ISTNRM_addr,RIO_FUNC,&Read_SB_ISTNRM,&Write_SB_ISTNRM);
sb_rio_register(SB_ISTEXT_addr,RIO_WF,0,&Write_SB_ISTEXT);
sb_rio_register(SB_ISTERR_addr,RIO_WF,0,&Write_SB_ISTERR);
//NRM
//6
sb_rio_register(SB_IML6NRM_addr,RIO_WF,0,&Write_SB_IML6NRM);
//4
sb_rio_register(SB_IML4NRM_addr,RIO_WF,0,&Write_SB_IML4NRM);
//2
sb_rio_register(SB_IML2NRM_addr,RIO_WF,0,&Write_SB_IML2NRM);
//EXT
//6
sb_rio_register(SB_IML6EXT_addr,RIO_WF,0,&Write_SB_IML6EXT);
//4
sb_rio_register(SB_IML4EXT_addr,RIO_WF,0,&Write_SB_IML4EXT);
//2
sb_rio_register(SB_IML2EXT_addr,RIO_WF,0,&Write_SB_IML2EXT);
//ERR
//6
sb_rio_register(SB_IML6ERR_addr,RIO_WF,0,&Write_SB_IML6ERR);
//4
sb_rio_register(SB_IML4ERR_addr,RIO_WF,0,&Write_SB_IML4ERR);
//2
sb_rio_register(SB_IML2ERR_addr,RIO_WF,0,&Write_SB_IML2ERR);
}
void asic_reg_Term()
@@ -212,6 +258,63 @@ void asic_reg_Term()
//Reset -> Reset - Initialise to default values
void asic_reg_Reset(bool hard)
{
if (hard)
{
sb_rio_register(SB_ISTEXT_addr, RIO_WF, 0, &Write_SB_ISTEXT);
sb_rio_register(SB_ISTERR_addr, RIO_WF, 0, &Write_SB_ISTERR);
if (settings.platform.isNaomi2())
{
sb_rio_register(SB_ISTNRM_addr, RIO_FUNC, &Read_SB_ISTNRM<true>, &Write_SB_ISTNRM<true>);
//NRM
//6
sb_rio_register(SB_IML6NRM_addr, RIO_WF, 0, &Write_SB_IML6NRM<true>);
//4
sb_rio_register(SB_IML4NRM_addr, RIO_WF, 0, &Write_SB_IML4NRM<true>);
//2
sb_rio_register(SB_IML2NRM_addr, RIO_WF, 0, &Write_SB_IML2NRM<true>);
//EXT
//6
sb_rio_register(SB_IML6EXT_addr, RIO_WF, 0, &Write_SB_IML6EXT<true>);
//4
sb_rio_register(SB_IML4EXT_addr, RIO_WF, 0, &Write_SB_IML4EXT<true>);
//2
sb_rio_register(SB_IML2EXT_addr, RIO_WF, 0, &Write_SB_IML2EXT<true>);
//ERR
//6
sb_rio_register(SB_IML6ERR_addr, RIO_WF, 0, &Write_SB_IML6ERR<true>);
//4
sb_rio_register(SB_IML4ERR_addr, RIO_WF, 0, &Write_SB_IML4ERR<true>);
//2
sb_rio_register(SB_IML2ERR_addr, RIO_WF, 0, &Write_SB_IML2ERR<true>);
}
else
{
sb_rio_register(SB_ISTNRM_addr, RIO_FUNC, &Read_SB_ISTNRM<false>, &Write_SB_ISTNRM<false>);
//NRM
//6
sb_rio_register(SB_IML6NRM_addr, RIO_WF, 0, &Write_SB_IML6NRM<false>);
//4
sb_rio_register(SB_IML4NRM_addr, RIO_WF, 0, &Write_SB_IML4NRM<false>);
//2
sb_rio_register(SB_IML2NRM_addr, RIO_WF, 0, &Write_SB_IML2NRM<false>);
//EXT
//6
sb_rio_register(SB_IML6EXT_addr, RIO_WF, 0, &Write_SB_IML6EXT<false>);
//4
sb_rio_register(SB_IML4EXT_addr, RIO_WF, 0, &Write_SB_IML4EXT<false>);
//2
sb_rio_register(SB_IML2EXT_addr, RIO_WF, 0, &Write_SB_IML2EXT<false>);
//ERR
//6
sb_rio_register(SB_IML6ERR_addr, RIO_WF, 0, &Write_SB_IML6ERR<false>);
//4
sb_rio_register(SB_IML4ERR_addr, RIO_WF, 0, &Write_SB_IML4ERR<false>);
//2
sb_rio_register(SB_IML2ERR_addr, RIO_WF, 0, &Write_SB_IML2ERR<false>);
}
}
}
+1
View File
@@ -3,6 +3,7 @@
void asic_RaiseInterrupt(HollyInterruptID inter);
void asic_CancelInterrupt(HollyInterruptID inter);
void asic_RaiseInterruptBothCLX(HollyInterruptID inter);
//Init/Res/Term for regs
void asic_reg_Init();
+165 -8
View File
@@ -26,34 +26,190 @@ std::array<RegisterStruct, 0x540> sb_regs;
// much empty space
u32 SB_ISTNRM;
u32 SB_ISTNRM1;
#define SB_REG_NAME(r) { r##_addr, #r },
const std::map<u32, const char *> sb_reg_names = {
SB_REG_NAME(SB_C2DSTAT)
SB_REG_NAME(SB_C2DLEN)
SB_REG_NAME(SB_C2DST)
SB_REG_NAME(SB_SDSTAW)
SB_REG_NAME(SB_SDBAAW)
SB_REG_NAME(SB_SDWLT)
SB_REG_NAME(SB_SDLAS)
SB_REG_NAME(SB_SDST)
SB_REG_NAME(SB_SDDIV)
SB_REG_NAME(SB_DBREQM)
SB_REG_NAME(SB_BAVLWC)
SB_REG_NAME(SB_C2DPRYC)
SB_REG_NAME(SB_C2DMAXL)
SB_REG_NAME(SB_TFREM)
SB_REG_NAME(SB_LMMODE0)
SB_REG_NAME(SB_LMMODE1)
SB_REG_NAME(SB_FFST)
SB_REG_NAME(SB_SFRES)
SB_REG_NAME(SB_SBREV)
SB_REG_NAME(SB_RBSPLT)
SB_REG_NAME(SB_ISTNRM)
SB_REG_NAME(SB_ISTEXT)
SB_REG_NAME(SB_ISTERR)
SB_REG_NAME(SB_IML2NRM)
SB_REG_NAME(SB_IML2EXT)
SB_REG_NAME(SB_IML2ERR)
SB_REG_NAME(SB_IML4NRM)
SB_REG_NAME(SB_IML4EXT)
SB_REG_NAME(SB_IML4ERR)
SB_REG_NAME(SB_IML6NRM)
SB_REG_NAME(SB_IML6EXT)
SB_REG_NAME(SB_IML6ERR)
SB_REG_NAME(SB_PDTNRM)
SB_REG_NAME(SB_PDTEXT)
SB_REG_NAME(SB_G2DTNRM)
SB_REG_NAME(SB_G2DTEXT)
SB_REG_NAME(SB_MDSTAR)
SB_REG_NAME(SB_MDTSEL)
SB_REG_NAME(SB_MDEN)
SB_REG_NAME(SB_MDST)
SB_REG_NAME(SB_MSYS)
SB_REG_NAME(SB_MST)
SB_REG_NAME(SB_MSHTCL)
SB_REG_NAME(SB_MDAPRO)
SB_REG_NAME(SB_MMSEL)
SB_REG_NAME(SB_MTXDAD)
SB_REG_NAME(SB_MRXDAD)
SB_REG_NAME(SB_MRXDBD)
SB_REG_NAME(SB_GDSTAR)
SB_REG_NAME(SB_GDLEN)
SB_REG_NAME(SB_GDDIR)
SB_REG_NAME(SB_GDEN)
SB_REG_NAME(SB_GDST)
SB_REG_NAME(SB_G1RRC)
SB_REG_NAME(SB_G1RWC)
SB_REG_NAME(SB_G1FRC)
SB_REG_NAME(SB_G1FWC)
SB_REG_NAME(SB_G1CRC)
SB_REG_NAME(SB_G1CWC)
SB_REG_NAME(SB_G1GDRC)
SB_REG_NAME(SB_G1GDWC)
SB_REG_NAME(SB_G1SYSM)
SB_REG_NAME(SB_G1CRDYC)
SB_REG_NAME(SB_GDAPRO)
SB_REG_NAME(SB_GDSTARD)
SB_REG_NAME(SB_GDLEND)
SB_REG_NAME(SB_ADSTAG)
SB_REG_NAME(SB_ADSTAR)
SB_REG_NAME(SB_ADLEN)
SB_REG_NAME(SB_ADDIR)
SB_REG_NAME(SB_ADTSEL)
SB_REG_NAME(SB_ADEN)
SB_REG_NAME(SB_ADST)
SB_REG_NAME(SB_ADSUSP)
SB_REG_NAME(SB_E1STAG)
SB_REG_NAME(SB_E1STAR)
SB_REG_NAME(SB_E1LEN)
SB_REG_NAME(SB_E1DIR)
SB_REG_NAME(SB_E1TSEL)
SB_REG_NAME(SB_E1EN)
SB_REG_NAME(SB_E1ST)
SB_REG_NAME(SB_E1SUSP)
SB_REG_NAME(SB_E2STAG)
SB_REG_NAME(SB_E2STAR)
SB_REG_NAME(SB_E2LEN)
SB_REG_NAME(SB_E2DIR)
SB_REG_NAME(SB_E2TSEL)
SB_REG_NAME(SB_E2EN)
SB_REG_NAME(SB_E2ST)
SB_REG_NAME(SB_E2SUSP)
SB_REG_NAME(SB_DDSTAG)
SB_REG_NAME(SB_DDSTAR)
SB_REG_NAME(SB_DDLEN)
SB_REG_NAME(SB_DDDIR)
SB_REG_NAME(SB_DDTSEL)
SB_REG_NAME(SB_DDEN)
SB_REG_NAME(SB_DDST)
SB_REG_NAME(SB_DDSUSP)
SB_REG_NAME(SB_G2ID)
SB_REG_NAME(SB_G2DSTO)
SB_REG_NAME(SB_G2TRTO)
SB_REG_NAME(SB_G2MDMTO)
SB_REG_NAME(SB_G2MDMW)
SB_REG_NAME(SB_G2APRO)
SB_REG_NAME(SB_ADSTAGD)
SB_REG_NAME(SB_ADSTARD)
SB_REG_NAME(SB_ADLEND)
SB_REG_NAME(SB_E1STAGD)
SB_REG_NAME(SB_E1STARD)
SB_REG_NAME(SB_E1LEND)
SB_REG_NAME(SB_E2STAGD)
SB_REG_NAME(SB_E2STARD)
SB_REG_NAME(SB_E2LEND)
SB_REG_NAME(SB_DDSTAGD)
SB_REG_NAME(SB_DDSTARD)
SB_REG_NAME(SB_DDLEND)
SB_REG_NAME(SB_PDSTAP)
SB_REG_NAME(SB_PDSTAR)
SB_REG_NAME(SB_PDLEN)
SB_REG_NAME(SB_PDDIR)
SB_REG_NAME(SB_PDTSEL)
SB_REG_NAME(SB_PDEN)
SB_REG_NAME(SB_PDST)
SB_REG_NAME(SB_PDAPRO)
SB_REG_NAME(SB_PDSTAPD)
SB_REG_NAME(SB_PDSTARD)
SB_REG_NAME(SB_PDLEND)
};
#undef SB_REG_NAME
static const char *regName(u32 addr)
{
static char regName[10];
auto it = sb_reg_names.find(addr & 0x7fffff); // (addr - 0x5f6800) & 0x1fff);
if (it == sb_reg_names.end())
{
sprintf(regName, "?%06x", addr& 0x7fffff);
return regName;
}
else
return it->second;
}
u32 sb_ReadMem(u32 addr,u32 sz)
{
u32 offset = (addr - SB_BASE) >> 2;
u32 offset = ((addr - SB_BASE) >> 2) & 0x1fff;
u32 rv;
if (!(sb_regs[offset].flags & (REG_RF|REG_WO)))
{
if (sz==4)
return sb_regs[offset].data32;
rv = sb_regs[offset].data32;
else if (sz==2)
return sb_regs[offset].data16;
rv = sb_regs[offset].data16;
else
return sb_regs[offset].data8;
rv = sb_regs[offset].data8;
}
else
{
if ((sb_regs[offset].flags & REG_WO) || sb_regs[offset].readFunctionAddr == NULL)
{
INFO_LOG(HOLLY, "sb_ReadMem write-only reg %08x %d", addr, sz);
return 0;
rv = 0;
}
return sb_regs[offset].readFunctionAddr(addr);
else
rv = sb_regs[offset].readFunctionAddr(addr);
}
if ((addr & 0xffffff) != 0x5f6c18) // SB_MDST
DEBUG_LOG(HOLLY, "read(%d) %s.%c == %x", sz, regName(addr),
((addr >> 26) & 7) == 2 ? 'b' : (addr & 0x2000000) ? '1' : '0',
rv);
return rv;
}
void sb_WriteMem(u32 addr,u32 data,u32 sz)
{
u32 offset = (addr - SB_BASE) >> 2;
DEBUG_LOG(HOLLY, "write(%d) %s.%c = %x", sz, regName(addr),
((addr >> 26) & 7) == 2 ? 'b' : (addr & 0x2000000) ? '1' : '0',
data);
u32 offset = ((addr - SB_BASE) >> 2) & 0x1fff;
if (!(sb_regs[offset].flags & REG_WF))
{
@@ -593,6 +749,7 @@ void sb_Reset(bool hard)
reg.reset();
}
SB_ISTNRM = 0;
SB_ISTNRM1 = 0;
SB_FFST_rc = 0;
SB_FFST = 0;
@@ -600,7 +757,7 @@ void sb_Reset(bool hard)
ModemReset();
asic_reg_Reset(hard);
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isConsole())
gdrom_reg_Reset(hard);
else
naomi_reg_Reset(hard);
+4
View File
@@ -4,6 +4,7 @@
#pragma once
#include "types.h"
#include "hw/hwreg.h"
#include <array>
u32 sb_ReadMem(u32 addr,u32 sz);
@@ -365,6 +366,9 @@ extern u32 SB_FFST;
//0x005F6900 SB_ISTNRM RW Normal interrupt status
extern u32 SB_ISTNRM;
//0x025F6900 SB_ISTNRM1 RW Normal interrupt status CLXB (Naomi 2)
extern u32 SB_ISTNRM1;
//0x005F6904 SB_ISTEXT R External interrupt status
#define SB_ISTEXT SB_REG_32(ISTEXT)
//0x005F6908 SB_ISTERR RW Error interrupt status
+56 -26
View File
@@ -31,6 +31,8 @@ static std::string getRomPrefix()
return "dc_";
case DC_PLATFORM_NAOMI:
return "naomi_";
case DC_PLATFORM_NAOMI2:
return "naomi2_";
case DC_PLATFORM_ATOMISWAVE:
return "aw_";
default:
@@ -107,7 +109,7 @@ static void add_isp_to_nvmem(DCFlashChip *flash)
static void fixUpDCFlash()
{
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isConsole())
{
static_cast<DCFlashChip*>(sys_nvmem)->Validate();
@@ -138,6 +140,7 @@ static void fixUpDCFlash()
memset(&syscfg, 0xff, sizeof(syscfg));
syscfg.time_lo = 0;
syscfg.time_hi = 0;
syscfg.time_zone = 0;
syscfg.lang = 0;
syscfg.mono = 0;
syscfg.autostart = 1;
@@ -158,19 +161,34 @@ static void fixUpDCFlash()
if (!memcmp(console_id, "\377\377\377\377\377\377", 6))
{
srand(now);
u8 sum = 0;
for (int i = 0; i < 6; i++)
{
console_id[i] = rand();
console_id[i + 0xA0] = console_id[i]; // copy at 1A0F8
sum += console_id[i];
}
console_id[-1] = console_id[0xA0 - 1] = sum;
console_id[-2] = console_id[0xA0 - 2] = ~sum;
}
else
{
// Fix checksum
u8 sum = 0;
for (int i = 0; i < 6; i++)
sum += console_id[i];
console_id[-1] = console_id[0xA0 - 1] = sum;
console_id[-2] = console_id[0xA0 - 2] = ~sum;
}
// must be != 0xff
console_id[7] = console_id[0xA0 + 7] = 0xfe;
}
}
static bool nvmem_load()
{
bool rc;
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isConsole())
rc = sys_nvmem->Load(getRomPrefix(), "%nvmem.bin", "nvram");
else
rc = sys_nvmem->Load(hostfs::getArcadeFlashPath() + ".nvmem");
@@ -180,7 +198,7 @@ static bool nvmem_load()
if (config::GGPOEnable)
sys_nvmem->digest(settings.network.md5.nvmem);
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
if (settings.platform.isAtomiswave())
{
sys_rom->Load(hostfs::getArcadeFlashPath() + ".nvmem2");
if (config::GGPOEnable)
@@ -193,7 +211,7 @@ static bool nvmem_load()
bool LoadRomFiles()
{
nvmem_load();
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
if (!settings.platform.isAtomiswave())
{
if (sys_rom->Load(getRomPrefix(), "%boot.bin;%boot.bin.bin;%bios.bin;%bios.bin.bin", "bootrom"))
{
@@ -201,7 +219,7 @@ bool LoadRomFiles()
sys_rom->digest(settings.network.md5.bios);
bios_loaded = true;
}
else if (settings.platform.system == DC_PLATFORM_DREAMCAST)
else if (settings.platform.isConsole())
return false;
}
@@ -210,11 +228,11 @@ bool LoadRomFiles()
void SaveRomFiles()
{
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isConsole())
sys_nvmem->Save(getRomPrefix(), "nvmem.bin", "nvmem");
else
sys_nvmem->Save(hostfs::getArcadeFlashPath() + ".nvmem");
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
if (settings.platform.isAtomiswave())
((WritableChip *)sys_rom)->Save(hostfs::getArcadeFlashPath() + ".nvmem2");
}
@@ -258,12 +276,16 @@ static void WriteAWBios(u32 addr, u32 data, u32 sz)
//0x00800000- 0x00FFFFFF :AICA- Wave Memory
//0x01000000- 0x01FFFFFF :Ext. Device
//0x02000000- 0x03FFFFFF* :Image Area* 2MB
// Naomi 2:
//0x025F6800- 0x025F69FF :PVR#2 system registers
//0x025F7C00- 0x025F7CFF :PVR#2 PVR i/f Control Reg.
//0x025F8000- 0x025F9FFF :PVR#2 TA / PVR Core Reg.
template<typename T, u32 System, bool Mirror>
T DYNACALL ReadMem_area0(u32 addr)
T DYNACALL ReadMem_area0(u32 paddr)
{
constexpr u32 sz = (u32)sizeof(T);
addr &= 0x01FFFFFF;
u32 addr = paddr & 0x01FFFFFF;
const u32 base = addr >> 21;
switch (expected(base, 2))
@@ -303,14 +325,14 @@ T DYNACALL ReadMem_area0(u32 addr)
}
// All SB registers
if (addr >= 0x005F6800 && addr <= 0x005F7CFF)
return (T)sb_ReadMem(addr, sz);
return (T)sb_ReadMem(paddr, sz);
// TA / PVR core registers
if (addr >= 0x005F8000 && addr <= 0x005F9FFF)
{
if (sz != 4)
// House of the Dead 2
return 0;
return (T)pvr_ReadReg(addr);
return (T)pvr_ReadReg(paddr);
}
break;
case 3:
@@ -331,10 +353,10 @@ T DYNACALL ReadMem_area0(u32 addr)
}
// AICA sound registers
if (addr >= 0x00700000 && addr <= 0x00707FFF)
return (T)ReadMem_aica_reg(addr, sz);
return ReadMem_aica_reg<T>(addr);
// AICA RTC registers
if (addr >= 0x00710000 && addr <= 0x0071000B)
return (T)ReadMem_aica_rtc(addr, sz);
return ReadMem_aica_rtc<T>(addr);
break;
case 4:
@@ -342,12 +364,15 @@ T DYNACALL ReadMem_area0(u32 addr)
case 6:
case 7:
// AICA ram
return (T)ReadMemArr<sz>(aica_ram.data, addr & ARAM_MASK);
return ReadMemArr<T>(aica_ram.data, addr & ARAM_MASK);
default:
// G2 Ext area
if (System == DC_PLATFORM_NAOMI)
return (T)libExtDevice_ReadMem_A0_010(addr, sz);
if (System == DC_PLATFORM_NAOMI || System == DC_PLATFORM_NAOMI2)
{
INFO_LOG(MEMORY, "Read<%d> from G2 Ext area not implemented @ %08x", sz, addr);
return (T)0;
}
else if (config::EmulateBBA)
return (T)bba_ReadMem(addr, sz);
else
@@ -358,10 +383,10 @@ T DYNACALL ReadMem_area0(u32 addr)
}
template<typename T, u32 System, bool Mirror>
void DYNACALL WriteMem_area0(u32 addr, T data)
void DYNACALL WriteMem_area0(u32 paddr, T data)
{
constexpr u32 sz = (u32)sizeof(T);
addr &= 0x01FFFFFF;//to get rid of non needed bits
u32 addr = paddr & 0x01FFFFFF;//to get rid of non needed bits
const u32 base = addr >> 21;
@@ -410,14 +435,14 @@ void DYNACALL WriteMem_area0(u32 addr, T data)
// All SB registers
if (addr >= 0x005F6800 && addr <= 0x005F7CFF)
{
sb_WriteMem(addr, data, sz);
sb_WriteMem(paddr, data, sz);
return;
}
// TA / PVR core registers
if (addr >= 0x005F8000 && addr <= 0x005F9FFF)
{
verify(sz == 4);
pvr_WriteReg(addr, data);
pvr_WriteReg(paddr, data);
return;
}
break;
@@ -439,13 +464,13 @@ void DYNACALL WriteMem_area0(u32 addr, T data)
// AICA sound registers
if (addr >= 0x00700000 && addr <= 0x00707FFF)
{
WriteMem_aica_reg(addr, data, sz);
WriteMem_aica_reg(addr, data);
return;
}
// AICA RTC registers
if (addr >= 0x00710000 && addr <= 0x0071000B)
{
WriteMem_aica_rtc(addr, data, sz);
WriteMem_aica_rtc(addr, data);
return;
}
break;
@@ -454,18 +479,18 @@ void DYNACALL WriteMem_area0(u32 addr, T data)
case 6:
case 7:
// AICA ram
WriteMemArr<sz>(aica_ram.data, addr & ARAM_MASK, data);
WriteMemArr(aica_ram.data, addr & ARAM_MASK, data);
return;
default:
// G2 Ext area
if (System == DC_PLATFORM_NAOMI)
libExtDevice_WriteMem_A0_010(addr, data, sz);
if (System == DC_PLATFORM_NAOMI || System == DC_PLATFORM_NAOMI2)
INFO_LOG(MEMORY, "Write<%d> to G2 Ext area not implemented @ %08x: %x", sz, addr, (u32)data);
else if (config::EmulateBBA)
bba_WriteMem(addr, data, sz);
return;
}
INFO_LOG(COMMON, "Write to area0_32 not implemented [Unassigned], addr=%x,data=%x,size=%d", addr, data, sz);
INFO_LOG(MEMORY, "Write to area0_32 not implemented [Unassigned], addr=%x,data=%x,size=%d", addr, data, sz);
}
//Init/Res/Term
@@ -497,6 +522,7 @@ void sh4_area0_Reset(bool hard)
reios_set_flash(sys_nvmem);
break;
case DC_PLATFORM_NAOMI:
case DC_PLATFORM_NAOMI2:
sys_rom = new RomChip(settings.platform.bios_size);
sys_nvmem = new SRamChip(settings.platform.flash_size);
break;
@@ -551,6 +577,10 @@ void map_area0_init()
area0_handler = registerHandler(DC_PLATFORM_NAOMI, false);
area0_mirror_handler = registerHandler(DC_PLATFORM_NAOMI, true);
break;
case DC_PLATFORM_NAOMI2:
area0_handler = registerHandler(DC_PLATFORM_NAOMI2, false);
area0_mirror_handler = registerHandler(DC_PLATFORM_NAOMI2, true);
break;
case DC_PLATFORM_ATOMISWAVE:
area0_handler = registerHandler(DC_PLATFORM_ATOMISWAVE, false);
area0_mirror_handler = registerHandler(DC_PLATFORM_ATOMISWAVE, true);
+71
View File
@@ -0,0 +1,71 @@
#pragma once
#include "types.h"
typedef u32 RegReadAddrFP(u32 addr);
typedef void RegWriteAddrFP(u32 addr, u32 data);
/*
Read Write Const
D D N -> 0 -> RIO_DATA
D F N -> WF -> RIO_WF
F F N -> RF|WF -> RIO_FUNC
D X N -> RO|WF -> RIO_RO
F X N -> RF|WF|RO -> RIO_RO_FUNC
D X Y -> CONST|RO|WF-> RIO_CONST
X F N -> RF|WF|WO -> RIO_WO_FUNC
*/
enum RegStructFlags
{
REG_RF = 8,
REG_WF = 16,
REG_RO = 32,
REG_WO = 64,
REG_NO_ACCESS = REG_RO | REG_WO,
};
enum RegIO
{
RIO_DATA = 0,
RIO_WF = REG_WF,
RIO_FUNC = REG_WF | REG_RF,
RIO_RO = REG_RO | REG_WF,
RIO_RO_FUNC = REG_RO | REG_RF | REG_WF,
RIO_CONST = REG_RO | REG_WF,
RIO_WO_FUNC = REG_WF | REG_RF | REG_WO,
RIO_NO_ACCESS = REG_WF | REG_RF | REG_NO_ACCESS
};
struct RegisterStruct
{
union
{
u32 data32; //stores data of reg variable [if used] 32b
u16 data16; //stores data of reg variable [if used] 16b
u8 data8; //stores data of reg variable [if used] 8b
RegReadAddrFP* readFunctionAddr; //stored pointer to reg read function
};
RegWriteAddrFP* writeFunctionAddr; //stored pointer to reg write function
u32 flags; //Access flags !
void reset()
{
if (!(flags & (REG_RO | REG_RF)))
data32 = 0;
}
};
template<typename T>
T ReadMemArr(const u8 *array, u32 addr)
{
return *(const T *)&array[addr];
}
template<typename T>
void WriteMemArr(u8 *array, u32 addr, T data)
{
*(T *)&array[addr] = data;
}
+3 -4
View File
@@ -71,7 +71,7 @@ void MapleConfigMap::GetInput(PlainJoystickState* pjs)
{
const MapleInputState& inputState = mapleInputState[playerNum()];
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isConsole())
{
pjs->kcode = inputState.kcode;
pjs->joy[PJAI_X1] = GetBtFromSgn(inputState.fullAxes[PJAI_X1]);
@@ -79,7 +79,7 @@ void MapleConfigMap::GetInput(PlainJoystickState* pjs)
pjs->trigger[PJTI_R] = inputState.halfAxes[PJTI_R];
pjs->trigger[PJTI_L] = inputState.halfAxes[PJTI_L];
}
else if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
else if (settings.platform.isAtomiswave())
{
#ifdef LIBRETRO
pjs->kcode = inputState.kcode;
@@ -209,7 +209,6 @@ static void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num
static void createNaomiDevices()
{
mcfg_DestroyDevices();
mcfg_Create(MDT_NaomiJamma, 0, 5);
if (settings.input.JammaSetup == JVS::Keyboard)
{
@@ -229,7 +228,6 @@ static void createNaomiDevices()
static void createAtomiswaveDevices()
{
mcfg_DestroyDevices();
// Looks like two controllers needs to be on bus 0 and 1 for digital inputs
// Then other devices on port 2 and 3 for analog axes, light guns, ...
mcfg_Create(MDT_SegaController, 0, 5);
@@ -347,6 +345,7 @@ void mcfg_CreateDevices()
createDreamcastDevices();
break;
case DC_PLATFORM_NAOMI:
case DC_PLATFORM_NAOMI2:
createNaomiDevices();
break;
case DC_PLATFORM_ATOMISWAVE:
+2 -2
View File
@@ -1331,7 +1331,7 @@ maple_device* maple_Create(MapleDeviceType type)
switch(type)
{
case MDT_SegaController:
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
if (!settings.platform.isAtomiswave())
rv = new maple_sega_controller();
else
rv = new maple_atomiswave_controller();
@@ -1358,7 +1358,7 @@ maple_device* maple_Create(MapleDeviceType type)
break;
case MDT_LightGun:
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
if (!settings.platform.isAtomiswave())
rv = new maple_lightgun();
else
rv = new atomiswave_lightgun();
+1 -1
View File
@@ -66,7 +66,7 @@ void maple_vblank()
maple_ddt_pending_reset = false;
}
}
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
if (settings.platform.isConsole())
maple_handle_reconnect();
}
+16 -13
View File
@@ -65,7 +65,7 @@ const char *GetCurrentGameButtonName(DreamcastKey key)
val >>= 1;
}
u32 arcade_key;
if (settings.platform.system == DC_PLATFORM_NAOMI)
if (settings.platform.isNaomi())
{
if (pos >= ARRAY_SIZE(naomi_button_mapping))
return nullptr;
@@ -643,8 +643,17 @@ maple_naomi_jamma::maple_naomi_jamma()
io_boards.push_back(std::unique_ptr<jvs_837_13844>(new jvs_837_13844(1, this)));
break;
case JVS::DualIOBoards4P:
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(1, this)));
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(2, this, 2)));
if (!strcmp(naomi_game_id, "VIRTUA ATHLETE"))
{
// reverse the board order so that P1 is P1
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(1, this, 2)));
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(2, this, 0)));
}
else
{
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(1, this)));
io_boards.push_back(std::unique_ptr<jvs_837_13551>(new jvs_837_13551(2, this, 2)));
}
break;
case JVS::LightGun:
io_boards.push_back(std::unique_ptr<jvs_namco_jyu>(new jvs_namco_jyu(1, this)));
@@ -847,7 +856,7 @@ void maple_naomi_jamma::handle_86_subcommand()
u8 channel = 0;
if (dma_count_in >= 3)
{
if (dma_buffer_in[1] > 31 && dma_buffer_in[1] != 0xff && dma_count_in >= 8) // TODO what is this?
if (subcode != 0x13 && dma_count_in >= 8)
{
node_id = dma_buffer_in[6];
len = dma_buffer_in[7];
@@ -972,7 +981,7 @@ void maple_naomi_jamma::handle_86_subcommand()
{
int address = dma_buffer_in[1];
int size = dma_buffer_in[2];
DEBUG_LOG(MAPLE, "EEprom write %08X %08X\n", address, size);
DEBUG_LOG(MAPLE, "EEprom write %08x %08x", address, size);
//printState(Command,buffer_in,buffer_in_len);
address = address % sizeof(eeprom);
size = std::min((int)sizeof(eeprom) - address, size);
@@ -1609,14 +1618,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
}
else
{
// specs:
//u16 x = mo_x_abs * 0xFFFF / 639;
//u16 y = (479 - mo_y_abs) * 0xFFFF / 479;
// Ninja Assault:
u32 xr = 0x19d - 0x37;
u32 yr = 0x1fe - 0x40;
x = mapleInputState[playerNum].absPos.x * xr / 639 + 0x37;
y = mapleInputState[playerNum].absPos.y * yr / 479 + 0x40;
x = mapleInputState[playerNum].absPos.x;
y = mapleInputState[playerNum].absPos.y;
}
LOGJVS("lightgun %4x,%4x ", x, y);
JVS_OUT(x >> 8); // X, MSB
+23 -6
View File
@@ -1,6 +1,7 @@
#include "_vmem.h"
#include "hw/aica/aica_if.h"
#include "hw/pvr/pvr_mem.h"
#include "hw/pvr/elan.h"
#include "hw/sh4/dyna/blockmanager.h"
#include "hw/sh4/sh4_mem.h"
#include "oslib/oslib.h"
@@ -24,6 +25,11 @@ static _vmem_WriteMem32FP* _vmem_WF32[HANDLER_COUNT];
//upper 8b of the address
static void* _vmem_MemInfo_ptr[0x100];
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
#define MAP_ERAM_START_OFFSET (MAP_ARAM_START_OFFSET+ARAM_SIZE)
void* _vmem_read_const(u32 addr,bool& ismem,u32 sz)
{
u32 page=addr>>24;
@@ -417,7 +423,8 @@ static void _vmem_set_p0_mappings()
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
{0x08000000, 0x0A000000, 0, 0, false}, // Area 2
{0x0A000000, 0x0C000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x10000000, 0x80000000, 0, 0, false}, // Area 4-7 (unused)
};
@@ -434,7 +441,7 @@ bool _vmem_reserve()
// Use vmem only if settings mandate so, and if we have proper exception handlers.
#if !defined(TARGET_NO_EXCEPTIONS)
if (!settings.dynarec.disable_nvmem)
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb);
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb, RAM_SIZE_MAX + VRAM_SIZE_MAX + ARAM_SIZE_MAX + elan::ELAN_RAM_SIZE);
#endif
return true;
}
@@ -451,6 +458,8 @@ static void _vmem_term_mappings()
vram.data = nullptr;
free_pages(aica_ram.data);
aica_ram.data = nullptr;
free_pages(elan::RAM);
elan::RAM = nullptr;
}
}
@@ -478,6 +487,8 @@ void _vmem_init_mappings()
aica_ram.size = ARAM_SIZE;
aica_ram.data = (u8*)malloc_pages(ARAM_SIZE);
elan::RAM = (u8*)malloc_pages(elan::ELAN_RAM_SIZE);
}
else {
NOTICE_LOG(VMEM, "Info: nvmem is enabled, with addr space of size %s", vmemstatus == MemType4GB ? "4GB" : "512MB");
@@ -493,7 +504,8 @@ void _vmem_init_mappings()
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
{0x08000000, 0x0A000000, 0, 0, false}, // Area 2
{0x0A000000, 0x0C000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x10000000, 0x20000000, 0, 0, false}, // Area 4-7 (unused)
// This is outside of the 512MB addr space. We map 8MB in all cases to help some games read past the end of aica ram
@@ -505,6 +517,7 @@ void _vmem_init_mappings()
aica_ram.data = &virt_ram_base[0x20000000]; // Points to the writable AICA addrspace
vram.data = &virt_ram_base[0x04000000]; // Points to first vram mirror (writable and lockable)
mem_b.data = &virt_ram_base[0x0C000000]; // Main memory, first mirror
elan::RAM = &virt_ram_base[0x0A000000];
}
else
{
@@ -520,7 +533,8 @@ void _vmem_init_mappings()
{0x85000000, 0x86000000, 0, 0, false}, // 32 bit path (unused)
{0x86000000, 0x87000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x87000000, 0x88000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x88000000, 0x8C000000, 0, 0, false}, // Area 2
{0x88000000, 0x8A000000, 0, 0, false}, // Area 2
{0x8A000000, 0x8C000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
{0x8C000000, 0x90000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x90000000, 0xA0000000, 0, 0, false}, // Area 4-7 (unused)
// P2
@@ -533,7 +547,8 @@ void _vmem_init_mappings()
{0xA5000000, 0xA6000000, 0, 0, false}, // 32 bit path (unused)
{0xA6000000, 0xA7000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0xA7000000, 0xA8000000, 0, 0, false}, // 32 bit path (unused) mirror
{0xA8000000, 0xAC000000, 0, 0, false}, // Area 2
{0xA8000000, 0xAA000000, 0, 0, false}, // Area 2
{0xAA000000, 0xAC000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
{0xAC000000, 0xB0000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0xB0000000, 0xC0000000, 0, 0, false}, // Area 4-7 (unused)
// P3
@@ -546,7 +561,8 @@ void _vmem_init_mappings()
{0xC5000000, 0xC6000000, 0, 0, false}, // 32 bit path (unused)
{0xC6000000, 0xC7000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0xC7000000, 0xC8000000, 0, 0, false}, // 32 bit path (unused) mirror
{0xC8000000, 0xCC000000, 0, 0, false}, // Area 2
{0xC8000000, 0xCA000000, 0, 0, false}, // Area 2
{0xCA000000, 0xCC000000, MAP_ERAM_START_OFFSET, elan::ELAN_RAM_SIZE, true}, // Area 2 (Elan RAM)
{0xCC000000, 0xD0000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0xD0000000, 0x100000000L, 0, 0, false}, // Area 4-7 (unused)
};
@@ -556,6 +572,7 @@ void _vmem_init_mappings()
aica_ram.data = &virt_ram_base[0x80800000]; // Points to the first AICA addrspace in P1
vram.data = &virt_ram_base[0x84000000]; // Points to first vram mirror (writable and lockable) in P1
mem_b.data = &virt_ram_base[0x8C000000]; // Main memory, first mirror in P1
elan::RAM = &virt_ram_base[0x8A000000];
vmem_4gb_space = true;
}
+1 -5
View File
@@ -15,7 +15,7 @@ struct vmem_mapping {
// Platform specific vmemory API
// To initialize (maybe) the vmem subsystem
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr);
VMemType vmem_platform_init(void **vmem_base_addr, void **sh4rcb_addr, size_t ramSize);
// To reset the on-demand allocated pages.
void vmem_platform_reset_mem(void *ptr, unsigned size_bytes);
// To handle a fault&allocate an ondemand page.
@@ -109,10 +109,6 @@ static inline bool _nvmem_4gb_space() {
}
void _vmem_bm_reset();
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
void _vmem_protect_vram(u32 addr, u32 size);
void _vmem_unprotect_vram(u32 addr, u32 size);
u32 _vmem_get_vram_offset(void *addr);
+59
View File
@@ -24,6 +24,7 @@ namespace memwatch
VramWatcher vramWatcher;
RamWatcher ramWatcher;
AicaRamWatcher aramWatcher;
ElanRamWatcher elanWatcher;
void AicaRamWatcher::protectMem(u32 addr, u32 size)
{
@@ -107,5 +108,63 @@ u32 AicaRamWatcher::getMemOffset(void *p)
return addr;
}
void ElanRamWatcher::protectMem(u32 addr, u32 size)
{
using namespace elan;
size = std::min(ELAN_RAM_SIZE - addr, size) & ~PAGE_MASK;
if (_nvmem_enabled())
{
mem_region_lock(virt_ram_base + 0x0a000000 + addr, size); // P0
if (_nvmem_4gb_space())
{
mem_region_lock(virt_ram_base + 0x8a000000 + addr, size); // P1
mem_region_lock(virt_ram_base + 0xaa000000 + addr, size); // P2
}
} else {
mem_region_lock(RAM + addr, size);
}
}
void ElanRamWatcher::unprotectMem(u32 addr, u32 size)
{
using namespace elan;
size = std::min(ELAN_RAM_SIZE - addr, size) & ~PAGE_MASK;
if (_nvmem_enabled())
{
mem_region_unlock(virt_ram_base + 0x0a000000 + addr, size); // P0
if (_nvmem_4gb_space())
{
mem_region_unlock(virt_ram_base + 0x8a000000 + addr, size); // P1
mem_region_unlock(virt_ram_base + 0xaa000000 + addr, size); // P2
}
} else {
mem_region_unlock(RAM + addr, size);
}
}
u32 ElanRamWatcher::getMemOffset(void *p)
{
using namespace elan;
u32 addr;
if (_nvmem_enabled())
{
if ((u8 *)p < virt_ram_base || (u8 *)p >= virt_ram_base + 0x100000000L)
return -1;
addr = (u32)((u8 *)p - virt_ram_base);
u32 area = (addr >> 29) & 7;
if (area != 0 && area != 4 && area != 5) // P0, P1 or P2 only
return -1;
addr &= 0x1fffffff;
if (addr < 0x0a000000 || addr >= 0x0a000000 + ELAN_RAM_SIZE)
return -1;
addr &= ELAN_RAM_MASK;
} else {
if ((u8 *)p < RAM || (u8 *)p >= &RAM[ELAN_RAM_SIZE])
return -1;
addr = (u32)((u8 *)p - RAM);
}
return addr;
}
}
+22
View File
@@ -22,6 +22,7 @@
#include "hw/sh4/dyna/blockmanager.h"
#include "hw/sh4/sh4_mem.h"
#include "hw/pvr/pvr_mem.h"
#include "hw/pvr/elan.h"
#include "rend/TexCache.h"
#include <array>
#include <unordered_map>
@@ -148,9 +149,26 @@ public:
}
};
class ElanRamWatcher : public Watcher<ElanRamWatcher>
{
friend class Watcher<ElanRamWatcher>;
protected:
void protectMem(u32 addr, u32 size);
void unprotectMem(u32 addr, u32 size);
u32 getMemOffset(void *p);
public:
void *getMemPage(u32 addr)
{
return &elan::RAM[addr];
}
};
extern VramWatcher vramWatcher;
extern RamWatcher ramWatcher;
extern AicaRamWatcher aramWatcher;
extern ElanRamWatcher elanWatcher;
inline static bool writeAccess(void *p)
{
@@ -166,6 +184,8 @@ inline static bool writeAccess(void *p)
VramLockedWrite((u8 *)p);
return true;
}
if (settings.platform.isNaomi2() && elanWatcher.hit(p))
return true;
return aramWatcher.hit(p);
}
@@ -176,6 +196,7 @@ inline static void protect()
vramWatcher.protect();
ramWatcher.protect();
aramWatcher.protect();
elanWatcher.protect();
}
inline static void reset()
@@ -183,6 +204,7 @@ inline static void reset()
vramWatcher.reset();
ramWatcher.reset();
aramWatcher.reset();
elanWatcher.reset();
}
}
+45 -10
View File
@@ -410,18 +410,53 @@ void AWCartridge::AdvancePtr(u32 size)
dma_offset += size;
}
std::string AWCartridge::GetGameId()
struct AtomiswaveBootID
{
if (RomSize < 0x30 + 0x20)
return "(ROM too small)";
char boardName[16]; // SYSTEM_X_APP
char vendorName[32];
char gameTitle[32];
char year[4];
char month[2];
char day[2];
u32 _unkn0;
u32 _unkn1;
u32 _unkn2;
u32 gamePC;
u32 _unkn3;
u32 testPC;
};
dma_offset = 0x30;
u32 limit = 0x20;
char *name = (char *)GetDmaPtr(limit);
std::string game_id(name, limit);
while (!game_id.empty() && game_id.back() == ' ')
game_id.pop_back();
return game_id;
bool AWCartridge::GetBootId(RomBootID *bootId)
{
if (RomSize < sizeof(AtomiswaveBootID))
return false;
AtomiswaveBootID awBootId;
u8 *p = (u8 *)&awBootId;
u32 size = sizeof(AtomiswaveBootID);
dma_offset = 0;
recalc_dma_offset(EPR);
while (size > 0)
{
u32 chunkSize = size;
void *src = GetDmaPtr(chunkSize);
if (chunkSize == 0)
return false;
memcpy(p, src, chunkSize);
p += chunkSize;
size -= chunkSize;
AdvancePtr(chunkSize);
}
memset(bootId, 0, sizeof(RomBootID));
memcpy(bootId->boardName, awBootId.boardName, sizeof(bootId->boardName));
memcpy(bootId->vendorName, awBootId.vendorName, sizeof(bootId->vendorName));
memcpy(bootId->gameTitle[0], awBootId.gameTitle, sizeof(bootId->gameTitle[0]));
bootId->gamePC = awBootId.gamePC;
bootId->testPC = awBootId.testPC;
bootId->year = atoi(std::string(awBootId.year, awBootId.year + 4).c_str());
bootId->month = atoi(std::string(awBootId.month, awBootId.month + 2).c_str());
bootId->day = atoi(std::string(awBootId.day, awBootId.day + 2).c_str());
return true;
}
void AWCartridge::Serialize(Serializer& ser) const
+1 -1
View File
@@ -25,7 +25,7 @@ public:
void *GetDmaPtr(u32 &size) override;
void AdvancePtr(u32 size) override;
std::string GetGameId() override;
bool GetBootId(RomBootID *bootId) override;
void SetKey(u32 key) override;
void Serialize(Serializer& ser) const override;
+115
View File
@@ -0,0 +1,115 @@
/*
Copyright 2022 flyinghead
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "card_reader.h"
#include "oslib/oslib.h"
namespace card_reader {
InitialDCardReader initialDCardReader;
bool CardReader::loadCard(u8 *cardData, u32 len)
{
std::string path = hostfs::getArcadeFlashPath() + ".card";
FILE *fp = nowide::fopen(path.c_str(), "rb");
if (fp == nullptr)
return false;
DEBUG_LOG(NAOMI, "Loading card file from %s", path.c_str());
if (fread(cardData, 1, len, fp) != len)
WARN_LOG(NAOMI, "Truncated or empty card file: %s" ,path.c_str());
fclose(fp);
return true;
}
void CardReader::saveCard(const u8 *cardData, u32 len)
{
std::string path = hostfs::getArcadeFlashPath() + ".card";
FILE *fp = nowide::fopen(path.c_str(), "wb");
if (fp == nullptr)
{
WARN_LOG(NAOMI, "Can't create card file %s: errno %d", path.c_str(), errno);
return;
}
DEBUG_LOG(NAOMI, "Saving card file to %s", path.c_str());
if (fwrite(cardData, 1, len, fp) != len)
WARN_LOG(NAOMI, "Truncated write to file: %s", path.c_str());
fclose(fp);
}
void InitialDCardReader::write(u8 b)
{
if (inBufferIdx == 0 && b == 5)
{
DEBUG_LOG(NAOMI, "Received RQ(5)");
handleCommand();
return;
}
inBuffer[inBufferIdx++] = b;
if (inBufferIdx >= 3)
{
if (inBuffer[0] != 2)
{
INFO_LOG(NAOMI, "Unexpected cmd start byte %x", inBuffer[0]);
inBufferIdx = 0;
return;
}
u32 len = inBuffer[1];
if (inBufferIdx < len + 2)
{
if (inBufferIdx == sizeof(inBuffer))
{
WARN_LOG(NAOMI, "Card reader buffer overflow");
inBufferIdx = 0;
}
return;
}
u32 crc = calcCrc(&inBuffer[1], inBufferIdx - 2);
if (crc != inBuffer[inBufferIdx - 1])
{
INFO_LOG(NAOMI, "Wrong crc: expected %x got %x", crc, inBuffer[inBufferIdx - 1]);
inBufferIdx = 0;
return;
}
DEBUG_LOG(NAOMI, "Received cmd %x len %d", inBuffer[2], inBuffer[1]);
outBuffer[outBufferLen++] = 6; // ACK
rxCommandLen = inBufferIdx - 3;
memcpy(rxCommand, inBuffer + 2, rxCommandLen);
inBufferIdx = 0;
}
}
u8 InitialDCardReader::read()
{
verify(outBufferIdx < outBufferLen);
u8 b = outBuffer[outBufferIdx++];
DEBUG_LOG(NAOMI, "Sending %x", b);
if (outBufferIdx == outBufferLen)
outBufferIdx = outBufferLen = 0;
return b;
}
void InitialDCardReader::insertCard()
{
cardInserted = loadCard(cardData, sizeof(cardData));
if (cardInserted)
INFO_LOG(NAOMI, "Card inserted");
}
}
+199
View File
@@ -0,0 +1,199 @@
/*
Copyright 2022 flyinghead
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
/*
Initial D card reader protocol (from my good friend Metallic)
>>> SEND PKT: [START 02][LEN][CMD][0][0][0]{optional data}[STOP 03][CRC]
<<< RECV ACK: [OK 06]
>>> SEND REQ: [RQ 05]
<<< RECV PKT: [START 02][LEN][CMD][RESULT1][RESULT2][RESULT3]{optional data}[STOP 03][CRC]
<<< RECV ERR: [15]
RESULT1 (SENSORS): binary value SSTCCCCC
S - Shutter state:
0 - "ERROR"
1 - "CLOSED"
2 - "OPEN"
3 - "NOW" (both open and close sensors)
T - Stocker (card dispenser) state:
0 - "NO" (empty)
1 - "OK" (full)
C - Card sensors:
0 - "NO CARD"
1 - "CARD EXIST (ENTER)" (card inserted in front of shutter)
18 - "CARD EXIST" (card loaded inside of reader)
other - "CARD EXIST (OTHER)"
RESULT2: char 01235QRSTUV`
Error ENUM "OK", "READ ERR", "WRITE ERR", "STOP ERR", "PRINT ERR", "READERR T1", "READERR T2", "READERR T3",
"READERR T12", "READERR T13", "READERR T23", "SHUT ERR"
RESULT3 (CMD_STATE): char 02345
State ENUM "OK", "DISABLE", "BUSY", "CARD WAIT", "NO CARD IN BOX"
Protocol dumps and more:
https://www.arcade-projects.com/threads/naomi-2-chihiro-triforce-card-reader-emulator-initial-d3-wmmt-mario-kart-f-zero-ax.814/
*/
#pragma once
#include "types.h"
#include "hw/sh4/modules/modules.h"
namespace card_reader {
class CardReader
{
protected:
u8 calcCrc(u8 *data, u32 len)
{
u32 crc = 0;
for (u32 i = 0; i < len; i++)
crc ^= data[i];
return crc;
}
bool loadCard(u8 *cardData, u32 len);
void saveCard(const u8 *cardData, u32 len);
};
class InitialDCardReader : public CardReader, SerialPipe
{
public:
void write(u8 b) override;
u8 read() override;
int available() override {
return outBufferLen - outBufferIdx;
}
void insertCard();
void init() {
serial_setPipe(this);
}
private:
enum Commands
{
CARD_INIT = 0x10,
CARD_GET_CARD_STATE = 0x20,
CARD_IS_PRESENT = 0x40, // cancel?
CARD_LOAD_CARD = 0xB0,
CARD_CLEAN_CARD = 0xA0,
CARD_READ = 0x33,
CARD_WRITE = 0x53,
CARD_WRITE_INFO = 0x7C,
CARD_PRINT = 0x78,
CARD_7A = 0x7A,
CARD_7D = 0x7D,
CARD_DOOR = 0xD0,
CARD_EJECT = 0x80,
CARD_NEW = 0xB0,
};
u8 getStatus1()
{
return ((doorOpen ? 2 : 1) << 6) | 0x20 | (cardInserted ? 0x18 : 0);
}
void handleCommand()
{
if (rxCommandLen == 0)
return;
outBuffer[outBufferLen++] = 2;
u32 crcIdx = outBufferLen;
u8 len = 6;
u8 status1 = getStatus1();
u8 status2 = '0';
u8 status3 = '0';
switch (rxCommand[0])
{
case CARD_DOOR:
doorOpen = rxCommand[4] == '1';
status1 = getStatus1();
break;
case CARD_NEW:
cardInserted = true;
doorOpen = false;
status1 = getStatus1();
break;
case CARD_WRITE:
memcpy(cardData, &rxCommand[7], sizeof(cardData));
saveCard(cardData, sizeof(cardData));
break;
case CARD_READ:
if (cardInserted && !doorOpen)
len = 6 + sizeof(cardData);
else
status3 = cardInserted ? '0' : '4';
break;
case CARD_EJECT:
cardInserted = false;
status1 = getStatus1();
break;
case CARD_IS_PRESENT:
case CARD_GET_CARD_STATE:
case CARD_INIT:
case CARD_7A:
case CARD_PRINT:
case CARD_WRITE_INFO:
case CARD_CLEAN_CARD:
break;
default:
WARN_LOG(NAOMI, "Unknown command %x", rxCommand[0]);
break;
}
outBuffer[outBufferLen++] = len;
outBuffer[outBufferLen++] = rxCommand[0];
outBuffer[outBufferLen++] = status1;
outBuffer[outBufferLen++] = status2;
outBuffer[outBufferLen++] = status3;
if (rxCommand[0] == CARD_READ && cardInserted && !doorOpen)
{
memcpy(&outBuffer[outBufferLen], cardData, sizeof(cardData));
outBufferLen += sizeof(cardData);
}
outBuffer[outBufferLen++] = 3;
outBuffer[outBufferLen] = calcCrc(&outBuffer[crcIdx], outBufferLen - crcIdx);
outBufferLen++;
}
u8 inBuffer[256];
u32 inBufferIdx;
u8 rxCommand[256];
u32 rxCommandLen;
u8 outBuffer[256];
u32 outBufferIdx;
u32 outBufferLen;
u8 cardData[207];
bool doorOpen = false;
bool cardInserted = false;
};
extern InitialDCardReader initialDCardReader;
inline static void insertCard() {
initialDCardReader.insertCard();
}
}
-11
View File
@@ -627,14 +627,3 @@ bool GDCartridge::Read(u32 offset, u32 size, void *dst)
memcpy(dst, &dimm_data[addr], std::min(size, dimm_data_size - addr));
return true;
}
std::string GDCartridge::GetGameId()
{
if (dimm_data_size < 0x30 + 0x20)
return "(ROM too small)";
std::string game_id((char *)(dimm_data + 0x30), 0x20);
while (!game_id.empty() && game_id.back() == ' ')
game_id.pop_back();
return game_id;
}
-1
View File
@@ -33,7 +33,6 @@ public:
void* GetDmaPtr(u32 &size) override;
void AdvancePtr(u32 size) override;
bool Read(u32 offset, u32 size, void* dst) override;
std::string GetGameId() override;
void SetGDRomName(const char *name, const char *parentName) { this->gdrom_name = name; this->gdrom_parent_name = parentName; }
+8 -13
View File
@@ -273,26 +273,21 @@ M4Cartridge::~M4Cartridge()
free(m_key_data);
}
std::string M4Cartridge::GetGameId()
bool M4Cartridge::GetBootId(RomBootID *bootId)
{
if (RomSize < 0x30 + 0x20)
return "(ROM too small)";
std::string game_id;
if (RomPtr[0] == 'N' && RomPtr[1] == 'A')
game_id = std::string((char *)(RomPtr + 0x30), 0x20);
else
if (RomSize < sizeof(RomBootID))
return false;
RomBootID *pBootId = (RomBootID *)RomPtr;
if (memcmp(pBootId->boardName, "NAOMI", 5))
{
rom_cur_address = 0;
enc_reset();
enc_fill();
game_id = std::string((char *)(buffer + 0x30), 0x20);
pBootId = (RomBootID *)buffer;
}
memcpy(bootId, pBootId, sizeof(RomBootID));
while (!game_id.empty() && game_id.back() == ' ')
game_id.pop_back();
return game_id;
return true;
}
void M4Cartridge::Serialize(Serializer& ser) const
+1 -1
View File
@@ -44,9 +44,9 @@ public:
void* GetDmaPtr(u32 &size) override;
void AdvancePtr(u32 size) override;
std::string GetGameId() override;
void Serialize(Serializer& ser) const override;
void Deserialize(Deserializer& deser) override;
bool GetBootId(RomBootID *bootId) override;
void SetKey(u32 key) override { this->m4id = key; }
void SetKeyData(u8 *key_data) override { this->m_key_data = key_data; }
+71 -6
View File
@@ -9,12 +9,12 @@
#include "hw/maple/maple_cfg.h"
#include "hw/sh4/sh4_sched.h"
#include "hw/sh4/modules/dmac.h"
#include "hw/aica/aica_if.h"
#include "naomi.h"
#include "naomi_cart.h"
#include "naomi_regs.h"
#include "naomi_m3comm.h"
#include "network/naomi_network.h"
#include "serialize.h"
//#define NAOMI_COMM
@@ -46,6 +46,9 @@ P-Z (0x50-0x5A)
static u8 BSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
static u8 GSerial[]="\xB7"/*CRC1*/"\x19"/*CRC2*/"0123234437897584372973927387463782196719782697849162342198671923649";
static u8 midiTxBuf[4];
static u32 midiTxBufIndex;
static unsigned int ShiftCRC(unsigned int CRC,unsigned int rounds)
{
const unsigned int Magic=0x10210000;
@@ -367,6 +370,10 @@ void naomi_process(u32 command, u32 offsetl, u32 parameterl, u32 parameterh)
DEBUG_LOG(NAOMI, "Naomi process 0x%04X 0x%04X 0x%04X 0x%04X", command, offsetl, parameterl, parameterh);
DEBUG_LOG(NAOMI, "Possible format 0 %d 0x%02X 0x%04X",command >> 15,(command & 0x7e00) >> 9, command & 0x1FF);
DEBUG_LOG(NAOMI, "Possible format 1 0x%02X 0x%02X", (command & 0xFF00) >> 8,command & 0xFF);
// command: param1 & 3f << 9 | param2
// offsetl, paraml, paramh: params 3 4 5
// HOLLY::SB_IML2EXT |= 8 when done
u32 param=(command&0xFF);
if (param==0xFF)
@@ -406,7 +413,8 @@ void WriteMem_naomi(u32 address, u32 data, u32 size)
INFO_LOG(NAOMI, "called without cartridge");
return;
}
if (address >= NAOMI_COMM2_CTRL_addr && address <= NAOMI_COMM2_STATUS1_addr && settings.platform.system == DC_PLATFORM_NAOMI)
if (address >= NAOMI_COMM2_CTRL_addr && address <= NAOMI_COMM2_STATUS1_addr
&& settings.platform.isNaomi())
m3comm.WriteMem(address, data, size);
else
CurrentCartridge->WriteMem(address, data, size);
@@ -532,7 +540,6 @@ void naomi_reg_Term()
}
#endif
m3comm.closeNetwork();
naomiNetwork.terminate();
}
void naomi_reg_Reset(bool hard)
@@ -565,13 +572,13 @@ void naomi_reg_Reset(bool hard)
reg_dimm_parameterh = 0;
reg_dimm_status = 0x11;
m3comm.closeNetwork();
naomiNetwork.terminate();
if (hard)
naomi_cart_Close();
}
static u8 aw_maple_devs;
static u64 coin_chute_time[4];
static u8 ffbOuput;
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
addr &= 0x7ff;
@@ -628,7 +635,8 @@ u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
case 0x288:
// ??? Dolphin Blue
return 0;
case 0x28c:
return ffbOuput;
}
INFO_LOG(NAOMI, "Unhandled read @ %x sz %d", addr, size);
return 0xFF;
@@ -646,7 +654,12 @@ void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size) {
case 0x288:
// ??? Dolphin Blue
return;
//case 0x28C: // Wheel force feedback?
case 0x28C: // Wheel force feedback
// bit 0 direction (0 pos, 1 neg)
// bit 1-4 strength
ffbOuput = data;
DEBUG_LOG(NAOMI, "AW output %02x", data);
return;
default:
break;
}
@@ -681,6 +694,8 @@ void naomi_Serialize(Serializer& ser)
ser << aw_maple_devs;
ser << coin_chute_time;
ser << aw_ram_test_skipped;
ser << midiTxBuf;
ser << midiTxBufIndex;
// TODO serialize m3comm?
}
void naomi_Deserialize(Deserializer& deser)
@@ -722,4 +737,54 @@ void naomi_Deserialize(Deserializer& deser)
deser >> coin_chute_time;
deser >> aw_ram_test_skipped;
}
if (deser.version() >= Deserializer::V27)
{
deser >> midiTxBuf;
deser >> midiTxBufIndex;
}
else
{
midiTxBufIndex = 0;
}
}
static void midiSend(u8 b1, u8 b2, u8 b3)
{
aica_midiSend(b1);
aica_midiSend(b2);
aica_midiSend(b3);
aica_midiSend((b1 ^ b2 ^ b3) & 0x7f);
}
static void forceFeedbackMidiReceiver(u8 data)
{
static float position = 8192.f;
static float torque;
position = std::min(16383.f, std::max(0.f, position + torque));
if (data & 0x80)
midiTxBufIndex = 0;
midiTxBuf[midiTxBufIndex] = data;
if (midiTxBufIndex == 3 && ((midiTxBuf[0] ^ midiTxBuf[1] ^ midiTxBuf[2]) & 0x7f) == midiTxBuf[3])
{
if (midiTxBuf[0] == 0x84)
torque = ((midiTxBuf[1] << 7) | midiTxBuf[2]) - 0x80;
else if (midiTxBuf[0] == 0xff)
{
torque = 0;
position = 8192;
}
// required: b1 & 0x1f == 0x10 && b1 & 0x40 == 0
midiSend(0x90, ((int)position >> 7) & 0x7f, (int)position & 0x7f);
// decoding from FFB Arcade Plugin (by Boomslangnz)
// https://github.com/Boomslangnz/FFBArcadePlugin/blob/master/Game%20Files/Demul.cpp
if (midiTxBuf[0] == 0x85 && midiTxBuf[1] == 0x3f)
MapleConfigMap::UpdateVibration(0, std::max(0.f, (float)(midiTxBuf[2] - 1) / 24.f), 0.f, 5);
}
midiTxBufIndex = (midiTxBufIndex + 1) % ARRAY_SIZE(midiTxBuf);
}
void initMidiForceFeedback()
{
aica_setMidiReceiver(forceFeedbackMidiReceiver);
}
+5
View File
@@ -25,3 +25,8 @@ extern u32 reg_dimm_offsetl;
extern u32 reg_dimm_parameterl;
extern u32 reg_dimm_parameterh;
extern u32 reg_dimm_status;
void initMidiForceFeedback();
u32 libExtDevice_ReadMem_A0_006(u32 addr, u32 size);
void libExtDevice_WriteMem_A0_006(u32 addr, u32 data, u32 size);
+105 -52
View File
@@ -37,6 +37,8 @@
#include "cfg/option.h"
#include "oslib/oslib.h"
#include "serialize.h"
#include "card_reader.h"
#include "naomi_flashrom.h"
Cartridge *CurrentCartridge;
bool bios_loaded = false;
@@ -75,7 +77,10 @@ static bool loadBios(const char *filename, Archive *child_archive, Archive *pare
for (int romid = 0; bios->blobs[romid].filename != NULL; romid++)
{
if (region == -1)
{
region = bios->blobs[romid].region;
config::Region.override(region);
}
else
{
if (bios->blobs[romid].region != (u32)region)
@@ -150,7 +155,7 @@ static bool loadBios(const char *filename, Archive *child_archive, Archive *pare
if (config::GGPOEnable)
md5.getDigest(settings.network.md5.bios);
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
if (settings.platform.isAtomiswave())
// Reload the writeable portion of the FlashROM
sys_rom->Reload();
@@ -187,12 +192,9 @@ void naomi_cart_LoadBios(const char *filename)
const char *bios = "naomi";
if (game->bios != nullptr)
bios = game->bios;
u32 region_flag = std::min((int)config::Region, (int)game->region_flag);
if (game->region_flag == REGION_EXPORT_ONLY)
region_flag = REGION_EXPORT;
if (!loadBios(bios, archive.get(), parent_archive.get(), region_flag))
if (!loadBios(bios, archive.get(), parent_archive.get(), config::Region))
{
WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", region_flag, bios);
WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", (int)config::Region, bios);
if (!loadBios(bios, archive.get(), parent_archive.get(), -1))
{
// If a specific BIOS is needed for this game, fail.
@@ -205,7 +207,7 @@ void naomi_cart_LoadBios(const char *filename)
bios_loaded = true;
}
static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
static void loadMameRom(const char *filename, LoadProgress *progress)
{
Game *game = FindGame(filename);
if (game == NULL)
@@ -395,11 +397,8 @@ static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
}
md5.getDigest(settings.network.md5.game);
}
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
if (naomi_game_id[0] == '\0')
strcpy(naomi_game_id, game->name);
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
// Default game name if ROM boot id isn't found
strcpy(naomi_game_id, game->name);
} catch (...) {
delete CurrentCartridge;
@@ -408,18 +407,8 @@ static void naomi_cart_LoadZip(const char *filename, LoadProgress *progress)
}
}
void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
static void loadDecryptedRom(const char* file, LoadProgress *progress)
{
naomi_cart_Close();
std::string extension = get_file_extension(file);
if (extension == "zip" || extension == "7z")
{
naomi_cart_LoadZip(file, progress);
return;
}
// Try to load BIOS from naomi.zip
if (!loadBios("naomi", NULL, NULL, config::Region))
{
@@ -437,6 +426,7 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
std::vector<u32> fsize;
u32 romSize = 0;
std::string extension = get_file_extension(file);
if (extension == "lst")
{
// LST file
@@ -567,8 +557,55 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
DEBUG_LOG(NAOMI, "Legacy ROM loaded successfully");
CurrentCartridge = new DecryptedCartridge(romBase, romSize);
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
}
void naomi_cart_LoadRom(const char* file, LoadProgress *progress)
{
naomi_cart_Close();
std::string extension = get_file_extension(file);
if (extension == "zip" || extension == "7z")
loadMameRom(file, progress);
else
loadDecryptedRom(file, progress);
RomBootID bootId;
if (CurrentCartridge->GetBootId(&bootId))
{
std::string gameId = trim_trailing_ws(std::string(bootId.gameTitle[0], &bootId.gameTitle[0][32]));
if (strlen(gameId.c_str()) > 0)
strcpy(naomi_game_id, gameId.c_str());
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s] region %x players %x vertical %x", naomi_game_id, (u8)bootId.country, bootId.cabinet, bootId.vertical);
if (gameId == "INITIAL D"
|| gameId == "INITIAL D Ver.2"
|| gameId == "INITIAL D Ver.3"
|| gameId == "INITIAL D CYCRAFT")
{
card_reader::initialDCardReader.init();
initMidiForceFeedback();
}
else if (gameId == "SAMPLE GAME MAX LONG NAME-") // Driving Simulator
{
initMidiForceFeedback();
}
}
else
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
}
void naomi_cart_ConfigureEEPROM()
{
if (!settings.platform.isNaomi())
return;
RomBootID bootId;
if (CurrentCartridge->GetBootId(&bootId)
&& (!memcmp(bootId.boardName, "NAOMI", 5) || !memcmp(bootId.boardName, "Naomi2", 6)))
configure_naomi_eeprom(&bootId);
else
WARN_LOG(NAOMI, "Can't read ROM boot ID");
}
void naomi_cart_Close()
@@ -586,6 +623,8 @@ int naomi_cart_GetPlatform(const char *path)
return DC_PLATFORM_NAOMI;
else if (game->cart_type == AW)
return DC_PLATFORM_ATOMISWAVE;
else if (game->bios != nullptr && !strcmp("naomi2", game->bios))
return DC_PLATFORM_NAOMI2;
else
return DC_PLATFORM_NAOMI;
}
@@ -638,19 +677,25 @@ void* Cartridge::GetPtr(u32 offset, u32& size)
return &RomPtr[offset];
}
std::string Cartridge::GetGameId() {
if (RomSize < 0x30 + 0x20)
return "(ROM too small)";
std::string game_id((char *)RomPtr + 0x30, 0x20);
if (game_id == "AWNAOMI " && RomSize >= 0xFF50)
bool NaomiCartridge::GetBootId(RomBootID *bootId)
{
if (RomSize < sizeof(RomBootID))
return false;
u8 *p = (u8 *)bootId;
u32 size = sizeof(RomBootID);
DmaOffset = 0;
while (size > 0)
{
game_id = std::string((char *)RomPtr + 0xFF30, 0x20);
u32 chunkSize = size;
void *src = GetDmaPtr(chunkSize);
if (chunkSize == 0)
return false;
memcpy(p, src, chunkSize);
p += chunkSize;
size -= chunkSize;
AdvancePtr(chunkSize);
}
while (!game_id.empty() && game_id.back() == ' ')
game_id.pop_back();
return game_id;
return true;
}
void* NaomiCartridge::GetDmaPtr(u32& size)
@@ -672,7 +717,7 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
switch(address & 255)
{
case 0x3c: // 5f703c: DIMM COMMAND
DEBUG_LOG(NAOMI, "DIMM COMMAND read<%d>", size);
//DEBUG_LOG(NAOMI, "DIMM COMMAND read<%d>", size);
return 0xffff; //reg_dimm_command
case 0x40: // 5f7040: DIMM OFFSETL
DEBUG_LOG(NAOMI, "DIMM OFFSETL read<%d>", size);
@@ -683,8 +728,8 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
case 0x48: // 5f7048: DIMM PARAMETERH
DEBUG_LOG(NAOMI, "DIMM PARAMETERH read<%d>", size);
return reg_dimm_parameterh;
case 0x04C: // 5f704c: DIMM STATUS
DEBUG_LOG(NAOMI, "DIMM STATUS read<%d>", size);
case 0x4c: // 5f704c: DIMM STATUS
DEBUG_LOG(NAOMI, "DIMM STATUS read<%d>: %x", size, reg_dimm_status);
return reg_dimm_status;
case NAOMI_ROM_OFFSETH_addr&255:
@@ -756,23 +801,24 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
reg_dimm_status |= 1;*/
}
reg_dimm_command = data;
DEBUG_LOG(NAOMI, "DIMM COMMAND Write: %X <= %X, %d", address, data, size);
DEBUG_LOG(NAOMI, "DIMM COMMAND Write<%d>: %x", size, data);
return;
case 0x40: // 5f7040: DIMM OFFSETL
reg_dimm_offsetl = data;
DEBUG_LOG(NAOMI, "DIMM OFFSETL Write: %X <= %X, %d", address, data, size);
DEBUG_LOG(NAOMI, "DIMM OFFSETL Write<%d>: %x", size, data);
return;
case 0x44: // 5f7044: DIMM PARAMETERL
reg_dimm_parameterl = data;
DEBUG_LOG(NAOMI, "DIMM PARAMETERL Write: %X <= %X, %d", address, data, size);
DEBUG_LOG(NAOMI, "DIMM PARAMETERL Write<%d>: %x", size, data);
return;
case 0x48: // 5f7048: DIMM PARAMETERH
reg_dimm_parameterh = data;
DEBUG_LOG(NAOMI, "DIMM PARAMETERH Write: %X <= %X, %d", address, data, size);
DEBUG_LOG(NAOMI, "DIMM PARAMETERH Write<%d>: %x", size, data);
return;
case 0x4C: // 5f704c: DIMM STATUS
DEBUG_LOG(NAOMI, "DIMM STATUS Write<%d>: %x", size, data);
if (data&0x100)
{
asic_CancelInterrupt(holly_EXP_PCI);
@@ -784,8 +830,7 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
fclose(ramd);*/
naomi_process(reg_dimm_command, reg_dimm_offsetl, reg_dimm_parameterl, reg_dimm_parameterh);
}
reg_dimm_status = data & ~0x100;
DEBUG_LOG(NAOMI, "DIMM STATUS Write: %X <= %X, %d", address, data, size);
reg_dimm_status = (data & ~0x100) | 1;
return;
//These are known to be valid on normal ROMs and DIMM board
@@ -853,6 +898,9 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
DEBUG_LOG(NAOMI, "naomi WriteMem: %X <= %X, %d", address, data, size);
return;
case NAOMI_LED_addr & 0xff:
return;
default: break;
}
DEBUG_LOG(NAOMI, "naomi?WTF? WriteMem: %X <= %X, %d", address, data, size);
@@ -951,16 +999,21 @@ u16 M2Cartridge::ReadCipheredData(u32 offset)
}
std::string M2Cartridge::GetGameId()
bool M2Cartridge::GetBootId(RomBootID *bootId)
{
std::string game_id = NaomiCartridge::GetGameId();
if ((game_id.size() < 2 || ((u8)game_id[0] == 0xff && (u8)game_id[1] == 0xff)) && RomSize >= 0x800050)
if (RomSize < sizeof(RomBootID))
return false;
RomBootID *pBootId = (RomBootID *)RomPtr;
if ((pBootId->gameTitle[0][0] == '\0'
|| ((u8)pBootId->gameTitle[0][0] == 0xff && (u8)pBootId->gameTitle[0][1] == 0xff)))
{
game_id = std::string((char *)RomPtr + 0x800030, 0x20);
while (!game_id.empty() && game_id.back() == ' ')
game_id.pop_back();
if (RomSize < 0x800000 + sizeof(RomBootID))
return false;
pBootId = (RomBootID *)(RomPtr + 0x800000);
}
return game_id;
memcpy(bootId, pBootId, sizeof(RomBootID));
return true;
}
void M2Cartridge::Serialize(Serializer& ser) const {
+42 -2
View File
@@ -5,6 +5,44 @@
#include "types.h"
#include "emulator.h"
struct RomBootID
{
char boardName[16];
char vendorName[32];
char gameTitle[8][32];
u16 year;
u8 month;
u8 day;
char gameID[4]; // copied to eeprom[3]
u16 romMode; // != 0 => offset | 0x20000000
u16 romWaitFlag; // != 0 => configure G1 BUS
u32 romWait[8]; // init values for SB_G1RRC, SB_G1RWC, SB_G1FRC, SB_G1FWC, SB_G1CRC, SB_G1CWC, SB_G1GDRC, SB_G1GDWC
u16 romID[22][3]; // M2/M4-type ROM checksums
u8 coinFlag[8][16];// Init instructions for EEPROM for each region
// b0: if 0, use default BIOS settings, if 1, use settings below
// b1: bit 0: vertical monitor, bit 1: forces attract mode sound off
// b2: coin chute type: 0 common, 1; individual
// b3: default coin setting (1-28)
// b4: coin 1 rate (for manual coin setting)
// b5: coin 2 rate (for manual coin setting)
// b6: credit rate (for manual coin setting)
// b7: bonus credit rate (for manual coin setting)
// b8-15: coin sequences
char sequence[8][32];// text ("CREDIT TO START", "CREDIT TO CONTINUE", ...)
u32 gameLoad[8][3]; // regions to copy from ROM to system RAM: offset, RAM address, length (offset=0xffffffff means end of list)
u32 testLoad[8][3]; // same for game test mode
u32 gamePC; // main game entry point
u32 testPC; // test mode entry point
u8 country; // supported regions bitmap
u8 cabinet; // supported # of players bitmap: b0 1 player, b1 2 players, ...
u8 resolution; // 0: 31kHz, 1: 15kHz
u8 vertical; // b0: horizontal mode, b1: vertical mode
u8 serialID; // if 1, check the ROM/DIMM board serial# eeprom
u8 _res[211]; // _res[210]: if 0xFF then the header is unencrypted. if not then the header is encrypted starting at offset 0x010.
// Note: this structure is copied to system RAM by the BIOS at location 0c01f400
};
class Cartridge
{
public:
@@ -23,11 +61,11 @@ public:
virtual void* GetPtr(u32 offset, u32& size);
virtual void* GetDmaPtr(u32 &size) = 0;
virtual void AdvancePtr(u32 size) = 0;
virtual std::string GetGameId();
virtual void Serialize(Serializer& ser) const {}
virtual void Deserialize(Deserializer& deser) {}
virtual void SetKey(u32 key) { }
virtual void SetKeyData(u8 *key_data) { }
virtual bool GetBootId(RomBootID *bootId) = 0;
protected:
u8* RomPtr;
@@ -45,6 +83,7 @@ public:
void AdvancePtr(u32 size) override {}
void Serialize(Serializer& ser) const override;
void Deserialize(Deserializer& deser) override;
bool GetBootId(RomBootID *bootId) override;
void SetKey(u32 key) override { this->key = key; }
@@ -75,7 +114,7 @@ public:
void Serialize(Serializer& ser) const override;
void Deserialize(Deserializer& deser) override;
void* GetDmaPtr(u32& size) override;
std::string GetGameId() override;
bool GetBootId(RomBootID *bootId) override;
private:
u8 naomi_cart_ram[64 * 1024];
@@ -91,6 +130,7 @@ void naomi_cart_LoadRom(const char* file, LoadProgress *progress);
void naomi_cart_Close();
int naomi_cart_GetPlatform(const char *path);
void naomi_cart_LoadBios(const char *filename);
void naomi_cart_ConfigureEEPROM();
extern char naomi_game_id[];
extern u8 *naomi_default_eeprom;
+190 -3
View File
@@ -22,6 +22,7 @@
#include "hw/flashrom/flashrom.h"
#include "hw/holly/sb_mem.h"
#include "hw/maple/maple_devs.h"
#include "cfg/option.h"
extern WritableChip *sys_nvmem;
@@ -88,8 +89,7 @@ void write_naomi_flash(u32 addr, u8 value)
// eeprom layout:
// Offset Size
// 0 2 CRC of bytes [2,17]
// 2 1 size of record (16, sometimes 1, ignored)
// 3 15 data
// 2 16 data
// 18 18 same record repeated
// 36 2 CRC of bytes [44,44+size[
// 38 1 record size
@@ -98,10 +98,27 @@ void write_naomi_flash(u32 addr, u8 value)
// 44 size*2 Record data, repeated twice
//
// The first record contains naomi bios settings, and the second one game-specific settings
// common settings:
// 2 b0 vertical screen
// b4 attract mode sound
// 3 Game serial ID (4 chars)
// 7 unknown (9 or x18)
// 8 b0: coin chute type (0 common, 1 individual)
// b4-5: cabinet type (0: 1P, 10: 2P, 20: 2P, 30: 4P)
// 9 coin setting (-1), 27 is manual
// 10 coin to credit
// 11 chute 1 multiplier
// 12 chute 2 multiplier
// 13 bonus adder (coins)
// 14 coin sequence: b0-3 seq 1, b4-7 seq 2
// 15 coin sequence: b0-3 seq 3, b4-7 seq 4
// 16 coin sequence: b0-3 seq 5, b4-7 seq 6
// 17 coin sequence: b0-3 seq 7, b4-7 seq 8
//
void write_naomi_eeprom(u32 offset, u8 value)
{
if (offset >= 3 && offset < 20)
if (offset >= 2 && offset < 18)
{
EEPROM[offset] = value;
EEPROM[offset + 18] = value;
@@ -121,3 +138,173 @@ void write_naomi_eeprom(u32 offset, u8 value)
else
WARN_LOG(NAOMI, "EEPROM record doesn't exist or is too short");
}
static u8 readEeprom(u32 offset)
{
return EEPROM[offset & 127];
}
static bool initEeprom(const RomBootID *bootId)
{
if (!memcmp(bootId->gameID, &EEPROM[3], sizeof(bootId->gameID)))
return false;
NOTICE_LOG(NAOMI, "Initializing Naomi EEPROM for game %.32s", bootId->gameTitle[0]);
for (int i = 0; i < 4; i++)
write_naomi_eeprom(3 + i, bootId->gameID[i]);
write_naomi_eeprom(7, 9); // FIXME 9 or 0x18?
if (bootId->cabinet & 8)
write_naomi_eeprom(8, 30);
else if (bootId->cabinet & 4)
write_naomi_eeprom(8, 20);
else if (bootId->cabinet & 2)
write_naomi_eeprom(8, 10);
else
write_naomi_eeprom(8, 0);
if (bootId->coinFlag[0][1] == 1)
{
// ROM-specific defaults
write_naomi_eeprom(2, bootId->coinFlag[0][3] | (((bootId->coinFlag[0][3] & 2) ^ 2) << 3));
write_naomi_eeprom(9, bootId->coinFlag[0][3] - 1);
write_naomi_eeprom(10, bootId->coinFlag[0][6]);
write_naomi_eeprom(11, bootId->coinFlag[0][4]);
write_naomi_eeprom(12, bootId->coinFlag[0][5]);
write_naomi_eeprom(13, bootId->coinFlag[0][7]);
write_naomi_eeprom(14, bootId->coinFlag[0][8] | (bootId->coinFlag[0][9] << 4));
write_naomi_eeprom(15, bootId->coinFlag[0][10] | (bootId->coinFlag[0][11] << 4));
write_naomi_eeprom(16, bootId->coinFlag[0][12] | (bootId->coinFlag[0][13] << 4));
write_naomi_eeprom(17, bootId->coinFlag[0][14] | (bootId->coinFlag[0][15] << 4));
}
else
{
// BIOS defaults
write_naomi_eeprom(2, (bootId->vertical & 2) ? 0x11 : 0x10);
write_naomi_eeprom(9, 0);
write_naomi_eeprom(10, 1);
write_naomi_eeprom(11, 1);
write_naomi_eeprom(12, 1);
write_naomi_eeprom(13, 0);
write_naomi_eeprom(14, 0x11);
write_naomi_eeprom(15, 0x11);
write_naomi_eeprom(16, 0x11);
write_naomi_eeprom(17, 0x11);
}
return true;
}
void configure_naomi_eeprom(const RomBootID *bootId)
{
initEeprom(bootId);
// Horizontal / vertical screen orientation
if (bootId->vertical & 2)
{
NOTICE_LOG(NAOMI, "EEPROM: vertical monitor orientation");
write_naomi_eeprom(2, readEeprom(2) | 1);
config::Rotate90.override(true);
}
else if (bootId->vertical & 1)
{
NOTICE_LOG(NAOMI, "EEPROM: horizontal monitor orientation");
write_naomi_eeprom(2, readEeprom(2) & ~1);
}
// Number of players
if (bootId->cabinet != 0)
{
int nPlayers = readEeprom(8) >> 4; // 0 to 3
if (!(bootId->cabinet & (1 << nPlayers)))
{
u8 coinChute = readEeprom(8) & 1;
if (bootId->cabinet & 8)
{
NOTICE_LOG(NAOMI, "EEPROM: 4-player cabinet");
write_naomi_eeprom(8, 0x30 | coinChute);
}
else if (bootId->cabinet & 4)
{
NOTICE_LOG(NAOMI, "EEPROM: 3-player cabinet");
write_naomi_eeprom(8, 0x20 | coinChute);
}
else if (bootId->cabinet & 2)
{
NOTICE_LOG(NAOMI, "EEPROM: 2-player cabinet");
write_naomi_eeprom(8, 0x10 | coinChute);
}
else if (bootId->cabinet & 1)
{
NOTICE_LOG(NAOMI, "EEPROM: 1-player cabinet");
write_naomi_eeprom(8, 0x00 | coinChute);
}
}
}
// Region
if (bootId->country != 0 && (bootId->country & (1 << config::Region)) == 0)
{
if (bootId->country & 2)
{
NOTICE_LOG(NAOMI, "Forcing region USA");
config::Region.override(1);
}
else if (bootId->country & 4)
{
NOTICE_LOG(NAOMI, "Forcing region Export");
config::Region.override(2);
}
else if (bootId->country & 1)
{
NOTICE_LOG(NAOMI, "Forcing region Japan");
config::Region.override(0);
}
else if (bootId->country & 8)
{
NOTICE_LOG(NAOMI, "Forcing region Korea");
config::Region.override(3);
}
naomi_cart_LoadBios(settings.content.path.c_str());
}
// Coin settings
if (config::ForceFreePlay)
write_naomi_eeprom(9, 27 - 1);
}
static u32 aw_crc32(const void *data, size_t len)
{
constexpr u32 POLY = 0xEDB88320;
const u8 *buffer = (const u8 *)data;
u32 crc = -1;
while (len--)
{
crc = crc ^ *buffer++;
for (int bit = 0; bit < 8; bit++)
{
if (crc & 1)
crc = (crc >> 1) ^ POLY;
else
crc = crc >> 1;
}
}
return ~crc;
}
void configure_maxspeed_flash(bool enableNetwork, bool master)
{
if (enableNetwork)
{
sys_nvmem->data[0x3358] = 0;
sys_nvmem->data[0x46ac] = 0;
sys_nvmem->data[0x335c] = !master;
sys_nvmem->data[0x46b0] = !master;
}
else
{
sys_nvmem->data[0x3358] = 1;
sys_nvmem->data[0x46ac] = 1;
}
u32 crc = aw_crc32(&sys_nvmem->data[0x2200], 0x1354);
*(u32 *)&sys_nvmem->data[0x34] = crc;
*(u32 *)&sys_nvmem->data[0x38] = crc;
*(u32 *)&sys_nvmem->data[0x84] = crc;
*(u32 *)&sys_nvmem->data[0x88] = crc;
crc = aw_crc32(&sys_nvmem->data[0x20], 0x44);
*(u32 *)&sys_nvmem->data[0x64] = crc;
*(u32 *)&sys_nvmem->data[0xb4] = crc;
}
+3
View File
@@ -20,6 +20,9 @@
*/
#pragma once
#include "types.h"
#include "naomi_cart.h"
void write_naomi_flash(u32 addr, u8 value);
void write_naomi_eeprom(u32 offset, u8 value);
void configure_naomi_eeprom(const RomBootID *bootId);
void configure_maxspeed_flash(bool enableNetwork, bool master);
+89 -108
View File
@@ -18,69 +18,89 @@
You should have received a copy of the GNU General Public License
along with flycast. If not, see <https://www.gnu.org/licenses/>.
*/
//
// Optical communication board (837-13691)
// Ring topology
// 10 Mbps
// Max packet size 0x4000
//
#include "naomi_m3comm.h"
#include "naomi_regs.h"
#include "hw/holly/sb.h"
#include "hw/sh4/sh4_mem.h"
#include "network/naomi_network.h"
#include "emulator.h"
#include <chrono>
#include <memory>
constexpr u16 COMM_CTRL_CPU_RAM = 1 << 0;
constexpr u16 COMM_CTRL_RESET = 1 << 5; // rising edge
constexpr u16 COMM_CTRL_G1DMA = 1 << 14; // active low
struct CommBoardStat
{
u16 transmode; // communication mode (0: master, positive value: slave)
u16 totalnode; // Total number of nodes (same value is entered in upper and lower 8 bits)
u16 nodeID; // Local node ID (the same value is entered in the upper and lower 8 bits)
u16 transcnt; // counter (value increases by 1 per frame)
u16 cts; // CTS timer value (for debugging)
u16 dma_rx_addr; // DMA receive address (for debugging)
u16 dma_rx_size; // DMA receive size (for debugging)
u16 dma_tx_addr; // DMA transmit address (for debugging)
u16 dma_tx_size; // DMA transmission size (for debugging)
u16 dummy[7];
};
static inline u16 swap16(u16 w)
{
return (w >> 8) | (w << 8);
}
static void vblankCallback(Event event, void *param) {
((NaomiM3Comm *)param)->vblank();
}
void NaomiM3Comm::closeNetwork()
{
network_stopping = true;
EventManager::unlisten(Event::VBlank, vblankCallback, this);
naomiNetwork.shutdown();
if (thread && thread->joinable())
thread->join();
}
void NaomiM3Comm::connectNetwork()
{
gui_display_notification("Network started", 5000);
packet_number = 0;
if (naomiNetwork.syncNetwork())
slot_count = naomiNetwork.getSlotCount();
slot_id = naomiNetwork.getSlotId();
if (slot_count >= 2)
{
slot_count = naomiNetwork.slotCount();
slot_id = naomiNetwork.slotId();
connectedState(true);
}
else
{
connectedState(false);
network_stopping = true;
naomiNetwork.shutdown();
connectedState();
EventManager::listen(Event::VBlank, vblankCallback, this);
}
}
void NaomiM3Comm::receiveNetwork()
bool NaomiM3Comm::receiveNetwork()
{
const u32 slot_size = swap16(*(u16*)&m68k_ram[0x204]);
const u32 packet_size = slot_size * slot_count;
std::unique_ptr<u8[]> buf(new u8[packet_size]);
if (naomiNetwork.receive(buf.get(), packet_size))
{
packet_number += slot_count - 1;
*(u16*)&comm_ram[6] = swap16(packet_number);
std::unique_lock<std::mutex> lock(mem_mutex);
memcpy(&comm_ram[0x100 + slot_size], buf.get(), packet_size);
}
u16 packetNumber;
if (!naomiNetwork.receive(buf.get(), packet_size, &packetNumber))
return false;
*(u16*)&comm_ram[6] = swap16(packetNumber);
memcpy(&comm_ram[0x100 + slot_size], buf.get(), packet_size);
return true;
}
void NaomiM3Comm::sendNetwork()
{
if (naomiNetwork.hasToken())
{
const u32 packet_size = swap16(*(u16*)&m68k_ram[0x204]) * slot_count;
std::unique_lock<std::mutex> lock(mem_mutex);
naomiNetwork.send(&comm_ram[0x100], packet_size);
packet_number++;
*(u16*)&comm_ram[6] = swap16(packet_number);
}
const u32 packet_size = swap16(*(u16*)&m68k_ram[0x204]) * slot_count;
naomiNetwork.send(&comm_ram[0x100], packet_size, packet_number);
packet_number++;
}
u32 NaomiM3Comm::ReadMem(u32 address, u32 size)
@@ -98,13 +118,13 @@ u32 NaomiM3Comm::ReadMem(u32 address, u32 size)
case NAOMI_COMM2_DATA_addr & 255:
{
u16 value;
if (comm_ctrl & 1)
if (comm_ctrl & COMM_CTRL_CPU_RAM)
value = *(u16*)&m68k_ram[comm_offset];
else
// TODO u16 *commram = (u16*)membank("comm_ram")->base();
value = *(u16*)&comm_ram[comm_offset];
value = swap16(value);
DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA %s read @ %04x: %x", (comm_ctrl & 1) ? "m68k ram" : "comm ram", comm_offset, value);
DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA %s read @ %04x: %x", (comm_ctrl & COMM_CTRL_CPU_RAM) ? "m68k ram" : "comm ram", comm_offset, value);
comm_offset += 2;
return value;
}
@@ -123,11 +143,8 @@ u32 NaomiM3Comm::ReadMem(u32 address, u32 size)
}
}
void NaomiM3Comm::connectedState(bool success)
void NaomiM3Comm::connectedState()
{
if (!success)
return;
memset(&comm_ram[0xf000], 0, 16);
comm_ram[0xf000] = 1;
comm_ram[0xf001] = 1;
@@ -136,39 +153,16 @@ void NaomiM3Comm::connectedState(bool success)
u32 slot_size = swap16(*(u16*)&m68k_ram[0x204]);
memset(&comm_ram[0], 0, 32);
// 80000
comm_ram[0] = 0;
comm_ram[1] = slot_id == 0 ? 0 : 1;
// 80002
comm_ram[2] = 0x01;
comm_ram[3] = 0x01;
// 80004
if (slot_id == 0)
{
comm_ram[4] = 0;
comm_ram[5] = 0;
}
else
{
comm_ram[4] = 1;
comm_ram[5] = 1;
}
// 80006: packet number
comm_ram[6] = 0;
comm_ram[7] = 0;
// 80008
comm_ram[8] = slot_id == 0 ? 0x78 : 0x73;
comm_ram[9] = slot_id == 0 ? 0x30 : 0xa2;
// 8000A
*(u16 *)(comm_ram + 10) = 0x100 + slot_size; // offset of recvd data
// 8000C
*(u16 *)(comm_ram + 12) = slot_size * slot_count; // recvd data size
// 8000E
*(u16 *)(comm_ram + 14) = 0x100; // offset of sent data
// 80010
*(u16 *)(comm_ram + 16) = 0x80 + slot_size * slot_count; // sent data size
// FIXME wrungp uses 100, others 80
CommBoardStat& stat = *(CommBoardStat *)&comm_ram[0];
memset(&stat, 0, sizeof(stat));
stat.transmode = swap16(slot_id == 0 ? 0 : 1);
stat.totalnode = slot_count | (slot_count << 8);
stat.nodeID = slot_id | (slot_id << 8);
stat.cts = swap16(slot_id == 0 ? 0x7830 : 0x73a2);
stat.dma_rx_addr = swap16(0x100 + slot_size);
stat.dma_rx_size = swap16(slot_size * slot_count);
stat.dma_tx_addr = swap16(0x100);
stat.dma_tx_size = swap16(slot_size * slot_count);
comm_status0 = 0xff01; // But 1 at connect time before f000 is read
comm_status1 = (slot_count << 8) | slot_id;
@@ -183,20 +177,19 @@ void NaomiM3Comm::WriteMem(u32 address, u32 data, u32 size)
// bit 1: comm RAM bank (seems R/O for SH4)
// bit 5: M68K Reset
// bit 6: ???
// bit 7: might be M68K IRQ 5 or 2
// bit 7: might be M68K IRQ 5 or 2 - set to 0 by nlCbIntr()
// bit 14: G1 DMA bus master 0 - active / 1 - disabled
// bit 15: 0 - enable / 1 - disable this device ???
if (data & (1 << 5))
if ((comm_ctrl & COMM_CTRL_RESET) == 0 && (data & COMM_CTRL_RESET) != 0)
{
DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL m68k reset");
memset(&comm_ram[0], 0, 32);
comm_status0 = 0; // varies...
comm_status1 = 0;
if (!thread || !thread->joinable())
startThread();
connectNetwork();
}
comm_ctrl = (u16)(data & ~(1 << 5));
//DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL set to %x", comm_ctrl);
comm_ctrl = (u16)data;
DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL = %x", comm_ctrl);
return;
case NAOMI_COMM2_OFFSET_addr & 255:
@@ -207,7 +200,7 @@ void NaomiM3Comm::WriteMem(u32 address, u32 data, u32 size)
case NAOMI_COMM2_DATA_addr & 255:
DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA written @ %04x %04x", comm_offset, (u16)data);
data = swap16(data);
if (comm_ctrl & 1)
if (comm_ctrl & COMM_CTRL_CPU_RAM)
*(u16*)&m68k_ram[comm_offset] = (u16)data;
else
*(u16*)&comm_ram[comm_offset] = (u16)data;
@@ -232,11 +225,10 @@ void NaomiM3Comm::WriteMem(u32 address, u32 data, u32 size)
bool NaomiM3Comm::DmaStart(u32 addr, u32 data)
{
if (comm_ctrl & 0x4000)
if (comm_ctrl & COMM_CTRL_G1DMA)
return false;
DEBUG_LOG(NAOMI, "NaomiM3Comm: DMA addr %08X <-> %04x len %d %s", SB_GDSTAR, comm_offset, SB_GDLEN, SB_GDDIR == 0 ? "OUT" : "IN");
std::unique_lock<std::mutex> lock(mem_mutex);
if (SB_GDDIR == 0)
{
// Network write
@@ -246,7 +238,8 @@ bool NaomiM3Comm::DmaStart(u32 addr, u32 data)
else
{
// Network read
if (SB_GDLEN == 32 && (comm_ctrl & 1) == 0)
/*
if (SB_GDLEN == 32 && (comm_ctrl & COMM_CTRL_CPU_RAM) == 0)
{
char buf[32 * 5 + 1];
buf[0] = 0;
@@ -257,42 +250,30 @@ bool NaomiM3Comm::DmaStart(u32 addr, u32 data)
}
DEBUG_LOG(NAOMI, "Comm RAM read @%x: %s", comm_offset, buf);
}
*/
for (u32 i = 0; i < SB_GDLEN; i++)
WriteMem8_nommu(SB_GDSTAR + i, comm_ram[comm_offset++]);
}
return true;
}
void NaomiM3Comm::startThread()
void NaomiM3Comm::vblank()
{
network_stopping = false;
thread = std::unique_ptr<std::thread>(new std::thread([this]() {
using the_clock = std::chrono::high_resolution_clock;
if ((comm_ctrl & COMM_CTRL_RESET) == 0 || comm_status1 == 0)
return;
connectNetwork();
the_clock::time_point token_time = the_clock::now();
while (!network_stopping)
{
naomiNetwork.pipeSlaves();
receiveNetwork();
if (slot_id == 0 && naomiNetwork.hasToken())
{
const auto target_duration = std::chrono::milliseconds(10);
auto duration = the_clock::now() - token_time;
if (duration < target_duration)
{
DEBUG_LOG(NAOMI, "Sleeping for %ld ms", (long)std::chrono::duration_cast<std::chrono::milliseconds>(target_duration - duration).count());
std::this_thread::sleep_for(target_duration - duration);
}
token_time = the_clock::now();
}
sendNetwork();
}
DEBUG_LOG(NAOMI, "Network thread exiting");
}));
using the_clock = std::chrono::high_resolution_clock;
the_clock::time_point start = the_clock::now();
try {
bool received = false;
do {
received = receiveNetwork();
} while (!received && the_clock::now() - start < std::chrono::milliseconds(100));
if (!received)
INFO_LOG(NETWORK, "No data received");
sendNetwork();
} catch (const FlycastException& e) {
comm_status0 = 0;
comm_status1 = 0;
}
}
+3 -10
View File
@@ -20,10 +20,6 @@
*/
#pragma once
#include "types.h"
#include <atomic>
#include <memory>
#include <mutex>
#include <thread>
class NaomiM3Comm
{
@@ -33,13 +29,13 @@ public:
bool DmaStart(u32 addr, u32 data);
void closeNetwork();
void vblank();
private:
void connectNetwork();
void receiveNetwork();
bool receiveNetwork();
void sendNetwork();
void connectedState(bool success);
void startThread();
void connectedState();
u16 comm_ctrl = 0xC000;
u16 comm_offset = 0;
@@ -51,7 +47,4 @@ private:
int slot_count = 0;
int slot_id = 0;
std::atomic<bool> network_stopping{ false };
std::unique_ptr<std::thread> thread;
std::mutex mem_mutex;
};
+1
View File
@@ -19,6 +19,7 @@ enum
NAOMI_COMM2_STATUS0_addr = 0x5F7024,
NAOMI_COMM2_STATUS1_addr = 0x5F7028,
NAOMI_LED_addr = 0x5F7068,
NAOMI_BOARDID_WRITE_addr = 0x5F7078,
NAOMI_BOARDID_READ_addr = 0x5F707C,
NAOMI_COMM_OFFSET_addr = 0x5F7050,
File diff suppressed because it is too large. Load diff
-10
View File
@@ -44,15 +44,6 @@ enum CartridgeType {
GD
};
enum RegionType {
REGION_JAPAN = 0,
REGION_USA = 1,
REGION_EXPORT = 2,
REGION_KOREA = 3,
REGION_AUSTRALIA = 4,
REGION_EXPORT_ONLY = 5
};
enum RotationType {
ROT0 = 0,
ROT270 = 3,
@@ -85,7 +76,6 @@ struct Game
u32 key;
const char *bios;
CartridgeType cart_type;
RegionType region_flag;
RotationType rotation_flag;
struct
{
+77
View File
@@ -601,3 +601,80 @@ static InputDescriptors fotns_inputs = AW_5_BUTTONS("LP", "HP", "BOOST", "LK", "
static InputDescriptors mslug6_inputs = AW_5_BUTTONS("SHOOT", "JUMP", "GRENADE", "METAL SLUG ATTACK", "SWITCH WEAPONS");
static InputDescriptors rumblef_inputs = AW_5_BUTTONS("LP", "SP", "Dodge", "LK", "SK");
static InputDescriptors kingrt66_inputs = {
{
{ NAOMI_BTN0_KEY, "HORN" },
{ NAOMI_BTN1_KEY, "WIPER" },
{ NAOMI_DOWN_KEY, "VIEW" },
{ NAOMI_BTN2_KEY, "SHIFT L", 0, NAOMI_DOWN_KEY }, // This button uses P2 inputs for P1
{ NAOMI_BTN3_KEY, "SHIFT H", 0, NAOMI_UP_KEY }, // This button uses P2 inputs for P1
{ NAOMI_BTN4_KEY, "SHIFT R", 0, NAOMI_LEFT_KEY | NAOMI_DOWN_KEY },
// This button uses P2 inputs for P1
NAO_START_DESC
NAO_BASE_BTN_DESC
},
{
{ "HANDLE", Full, 0 },
{ "ACCEL", Half, 4 },
{ "BRAKE", Half, 5 },
},
};
static InputDescriptors clubkart_inputs = {
{
{ NAOMI_DOWN_KEY, "VIEW" },
NAO_START_DESC
NAO_BASE_BTN_DESC
},
{
{ "HANDLE", Full, 0 },
{ "ACCEL", Half, 4 },
{ "BRAKE", Half, 5 },
},
};
static InputDescriptors initd_inputs = {
{
{ NAOMI_DOWN_KEY, "VIEW" },
{ NAOMI_BTN0_KEY, "GEAR UP", 0, NAOMI_UP_KEY }, // This button uses P2 inputs for P1
{ NAOMI_BTN1_KEY, "GEAR DOWN", 0, NAOMI_DOWN_KEY }, // This button uses P2 inputs for P1
NAO_START_DESC
NAO_BASE_BTN_DESC
},
{
{ "HANDLE", Full, 0 },
{ "ACCEL", Half, 4 },
{ "BRAKE", Half, 5 },
},
};
static InputDescriptors wldrider_inputs = {
{
{ NAOMI_UP_KEY, "PUSH", NAOMI_LEFT_KEY },
{ NAOMI_DOWN_KEY, "PULL", NAOMI_RIGHT_KEY },
NAO_START_DESC
NAO_BASE_BTN_DESC
},
{
{ "Handlebar", Full, 0 },
{ "Accelerator", Half, 4 },
{ "Front Brake", Half, 5 },
{ "Rear Brake", Full, 2 },
},
};
static InputDescriptors soulsurfer_inputs = {
{
{ NAOMI_LEFT_KEY, "LEFT", NAOMI_BTN0_KEY },
{ NAOMI_RIGHT_KEY, "RIGHT", NAOMI_BTN1_KEY },
{ NAOMI_BTN4_KEY, "FLOORMAT" }, // TODO this should always be on
NAO_START_DESC
NAO_BASE_BTN_DESC
},
{
{ "SWING", Full, 2 },
{ "ROLL", Full, 0 },
{ "PITCH", Full, 1, true },
},
};
+26 -169
View File
@@ -1,7 +1,5 @@
#include "Renderer_if.h"
#include "spg.h"
#include "cheats.h"
#include "hw/mem/_vmem.h"
#include "hw/pvr/pvr_mem.h"
#include "rend/TexCache.h"
#include "cfg/option.h"
@@ -10,7 +8,6 @@
#include "serialize.h"
#include <mutex>
#include <zlib.h>
void retro_rend_present();
#ifndef LIBRETRO
@@ -42,160 +39,8 @@ static bool pend_rend;
TA_context* _pvrrc;
static void dump_frame(const char* file, TA_context* ctx, u8* vram, const u8* vram_ref = NULL) {
FILE* fw = fopen(file, "wb");
//append to it
fseek(fw, 0, SEEK_END);
u32 bytes = ctx->tad.End() - ctx->tad.thd_root;
fwrite("TAFRAME4", 1, 8, fw);
fwrite(&ctx->rend.isRTT, 1, sizeof(ctx->rend.isRTT), fw);
u32 zero = 0;
fwrite(&zero, 1, sizeof(bool), fw); // Was autosort
fwrite(&ctx->rend.fb_X_CLIP.full, 1, sizeof(ctx->rend.fb_X_CLIP.full), fw);
fwrite(&ctx->rend.fb_Y_CLIP.full, 1, sizeof(ctx->rend.fb_Y_CLIP.full), fw);
fwrite(ctx->rend.global_param_op.head(), 1, sizeof(PolyParam), fw);
fwrite(ctx->rend.verts.head(), 1, 4 * sizeof(Vertex), fw);
u32 t = VRAM_SIZE;
fwrite(&t, 1, sizeof(t), fw);
u8* compressed;
uLongf compressed_size;
u8* src_vram = vram;
if (vram_ref) {
src_vram = (u8*)malloc(VRAM_SIZE);
for (u32 i = 0; i < VRAM_SIZE; i++) {
src_vram[i] = vram[i] ^ vram_ref[i];
}
}
compressed = (u8*)malloc(VRAM_SIZE+16);
compressed_size = VRAM_SIZE;
verify(compress(compressed, &compressed_size, src_vram, VRAM_SIZE) == Z_OK);
fwrite(&compressed_size, 1, sizeof(compressed_size), fw);
fwrite(compressed, 1, compressed_size, fw);
free(compressed);
if (src_vram != vram)
free(src_vram);
fwrite(&bytes, 1, sizeof(t), fw);
compressed = (u8*)malloc(bytes + 16);
compressed_size = VRAM_SIZE;
verify(compress(compressed, &compressed_size, ctx->tad.thd_root, bytes) == Z_OK);
fwrite(&compressed_size, 1, sizeof(compressed_size), fw);
fwrite(compressed, 1, compressed_size, fw);
free(compressed);
fwrite(&ctx->tad.render_pass_count, 1, sizeof(u32), fw);
for (u32 i = 0; i < ctx->tad.render_pass_count; i++) {
u32 offset = ctx->tad.render_passes[i] - ctx->tad.thd_root;
fwrite(&offset, 1, sizeof(offset), fw);
}
fwrite(pvr_regs, 1, sizeof(pvr_regs), fw);
fclose(fw);
}
TA_context* read_frame(const char* file, u8* vram_ref = NULL) {
FILE* fw = fopen(file, "rb");
if (fw == NULL)
die("Cannot open frame to display");
char id0[8] = { 0 };
u32 t = 0;
if (fread(id0, 1, 8, fw) != 8) {
fclose(fw);
return 0;
}
if (memcmp(id0, "TAFRAME", 7) != 0 || (id0[7] != '3' && id0[7] != '4')) {
fclose(fw);
return 0;
}
u32 sizeofPolyParam = sizeof(PolyParam);
u32 sizeofVertex = sizeof(Vertex);
if (id0[7] == '3')
{
sizeofPolyParam -= 12;
sizeofVertex -= 16;
}
TA_context* ctx = tactx_Alloc();
ctx->Reset();
ctx->tad.Clear();
verify(fread(&ctx->rend.isRTT, 1, sizeof(ctx->rend.isRTT), fw) == sizeof(ctx->rend.isRTT));
verify(fread(&t, 1, sizeof(bool), fw) == sizeof(bool)); // Was autosort
verify(fread(&ctx->rend.fb_X_CLIP.full, 1, sizeof(ctx->rend.fb_X_CLIP.full), fw) == sizeof(ctx->rend.fb_X_CLIP.full));
verify(fread(&ctx->rend.fb_Y_CLIP.full, 1, sizeof(ctx->rend.fb_Y_CLIP.full), fw) == sizeof(ctx->rend.fb_Y_CLIP.full));
verify(fread(ctx->rend.global_param_op.Append(), 1, sizeofPolyParam, fw) == sizeofPolyParam);
Vertex *vtx = ctx->rend.verts.Append(4);
for (int i = 0; i < 4; i++)
verify(fread(vtx + i, 1, sizeofVertex, fw) == sizeofVertex);
verify(fread(&t, 1, sizeof(t), fw) == sizeof(t));
verify(t == VRAM_SIZE);
_vmem_unprotect_vram(0, VRAM_SIZE);
uLongf compressed_size;
verify(fread(&compressed_size, 1, sizeof(compressed_size), fw) == sizeof(compressed_size));
u8* gz_stream = (u8*)malloc(compressed_size);
verify(fread(gz_stream, 1, compressed_size, fw) == compressed_size);
uLongf tl = t;
verify(uncompress(vram.data, &tl, gz_stream, compressed_size) == Z_OK);
free(gz_stream);
verify(fread(&t, 1, sizeof(t), fw) == sizeof(t));
verify(fread(&compressed_size, 1, sizeof(compressed_size), fw) == sizeof(compressed_size));
gz_stream = (u8*)malloc(compressed_size);
verify(fread(gz_stream, 1, compressed_size, fw) == compressed_size);
tl = t;
verify(uncompress(ctx->tad.thd_data, &tl, gz_stream, compressed_size) == Z_OK);
free(gz_stream);
ctx->tad.thd_data += t;
if (fread(&t, 1, sizeof(t), fw) > 0) {
ctx->tad.render_pass_count = t;
for (u32 i = 0; i < t; i++) {
u32 offset;
verify(fread(&offset, 1, sizeof(offset), fw) == sizeof(offset));
ctx->tad.render_passes[i] = ctx->tad.thd_root + offset;
}
}
verify(fread(pvr_regs, 1, sizeof(pvr_regs), fw) == sizeof(pvr_regs));
fclose(fw);
return ctx;
}
bool dump_frame_switch = false;
static bool rend_frame(TA_context* ctx)
{
if (dump_frame_switch) {
char name[32];
sprintf(name, "dcframe-%d", FrameCount);
dump_frame(name, _pvrrc, &vram[0]);
dump_frame_switch = false;
}
bool proc = renderer->Process(ctx);
if (!proc || (!ctx->rend.isRTT && !ctx->rend.isRenderFramebuffer))
@@ -343,11 +188,29 @@ void rend_reset()
fb_w_cur = 1;
}
void rend_start_render()
void rend_start_render(TA_context *ctx)
{
render_called = true;
pend_rend = false;
TA_context* ctx = tactx_Pop(CORE_CURRENT_CTX);
if (ctx == nullptr)
{
u32 addresses[MAX_PASSES];
int count = getTAContextAddresses(addresses);
if (count > 0)
{
ctx = tactx_Pop(addresses[0]);
if (ctx != nullptr)
{
TA_context *linkedCtx = ctx;
for (int i = 1; i < count; i++)
{
linkedCtx->nextContext = tactx_Pop(addresses[i]);
if (linkedCtx->nextContext != nullptr)
linkedCtx = linkedCtx->nextContext;
}
}
}
}
// No end of render interrupt when rendering the framebuffer
if (!ctx || !ctx->rend.isRenderFramebuffer)
@@ -371,6 +234,8 @@ void rend_start_render()
FillBGP(ctx);
ctx->rend.isRTT = (FB_W_SOF1 & 0x1000000) != 0;
ctx->rend.fb_W_SOF1 = FB_W_SOF1;
ctx->rend.fb_W_CTRL.full = FB_W_CTRL.full;
ctx->rend.fb_X_CLIP = FB_X_CLIP;
ctx->rend.fb_Y_CLIP = FB_Y_CLIP;
@@ -380,7 +245,7 @@ void rend_start_render()
ctx->rend.fog_clamp_max = FOG_CLAMP_MAX;
}
if (!config::DelayFrameSwapping)
if (!config::DelayFrameSwapping && !ctx->rend.isRTT)
ggpo::endOfFrame();
palette_update();
if (QueueRender(ctx))
@@ -405,21 +270,13 @@ void rend_vblank()
if (!render_called && fb_dirty && FB_R_CTRL.fb_enable)
{
DEBUG_LOG(PVR, "Direct framebuffer write detected");
u32 saved_ctx_addr = PARAM_BASE;
bool restore_ctx = ta_ctx != NULL;
PARAM_BASE = 0xF00000;
SetCurrentTARC(CORE_CURRENT_CTX);
ta_ctx->Reset();
ta_ctx->rend.isRenderFramebuffer = true;
rend_start_render();
PARAM_BASE = saved_ctx_addr;
if (restore_ctx)
SetCurrentTARC(CORE_CURRENT_CTX);
TA_context *ctx = tactx_Alloc();
ctx->rend.isRenderFramebuffer = true;
rend_start_render(ctx);
fb_dirty = false;
}
render_called = false;
check_framebuffer_write();
cheatManager.apply();
emu.vblank();
}
+1 -1
View File
@@ -8,7 +8,7 @@ extern u32 FrameCount;
void rend_init_renderer();
void rend_term_renderer();
void rend_vblank();
void rend_start_render();
void rend_start_render(TA_context *ctx = nullptr);
void rend_end_render();
void rend_cancel_emu_wait();
bool rend_single_frame(const bool& enabled);
+1805
View File
File diff suppressed because it is too large. Load diff
+37
View File
@@ -0,0 +1,37 @@
/*
Copyright 2022 flyinghead
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "types.h"
namespace elan {
void init();
void reset(bool hard);
void term();
void vmem_init();
void vmem_map(u32 base);
void serialize(Serializer& ser);
void deserialize(Deserializer& deser);
extern u8 *RAM;
constexpr u32 ELAN_RAM_SIZE = 32 * 1024 * 1024;
constexpr u32 ELAN_RAM_MASK = ELAN_RAM_SIZE - 1;
}
+575
View File
@@ -0,0 +1,575 @@
/*
Copyright 2022 flyinghead
This file is part of Flycast.
Flycast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Flycast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "types.h"
namespace elan
{
union PCW
{
enum Command {
null = 0,
_matrix2 = 1,
_matrix1 = 2,
projMatrix = 3,
matrixOrLight = 4,
gmp = 5,
ich = 7,
model = 8,
registerWait = 0xe,
link = 0xf
};
struct
{
// Obj Control
u32 uv16bit : 1;
u32 gouraud : 1;
u32 offset : 1;
u32 texture : 1;
u32 colType : 2;
u32 volume : 1;
u32 shadow : 1;
// Naomi 2
u32 n2Command : 4;
u32 reserved : 4;
// Group Control
u32 userClip : 2;
u32 stripLen : 2;
u32 parallelLight:1;
u32 res_2 : 2;
u32 groupEnable : 1;
// Para Control
u32 listType : 3;
u32 naomi2 : 1;
u32 endOfStrip : 1;
u32 paraType : 3;
};
u8 objectControl;
u32 full;
};
struct ElanBase
{
PCW pcw;
};
struct Model : public ElanBase
{
// 08000800
struct {
u32 _res:27;
u32 cwCulling:1;
u32 openVolume:1;
u32 _res0:3;
} param;
TSP tsp;
u32 zero; // 0
u32 offset;
u32 one; // 1
u32 size;
u32 _res0; // 0
};
static_assert(sizeof(Model) % 32 == 0, "Invalid size for Model");
struct InstanceMatrix : public ElanBase
{
// 08000400
u32 id1; // f
u32 id2; // 7f
u32 _res[5];
u32 _res1; // 08000200
float envMapU; // env map U offset
float lm00;
float lm10;
float lm20;
float lm01;
float lm11;
float lm21;
float lm02;
float lm12;
float lm22;
float envMapV; // env map V offset
float _res2[4];
u32 _res3; // 08000100
float _near;
float tm00;
float tm01;
float tm02;
float tm10;
float tm11;
float tm12;
float tm20;
float tm21;
float tm22;
float tm30;
float tm31;
float tm32;
float _far;
float mproj6; // 1 / near
bool isInstanceMatrix() const {
return id1 == 0xf && id2 == 0x7f;
}
};
static_assert(sizeof(InstanceMatrix) % 32 == 0, "Invalid size for InstanceMatrix");
struct ProjMatrix : public ElanBase
{
// 08000300
u32 _res;
float fx, tx;
float fy, ty;
u32 _res0[2];
};
static_assert(sizeof(ProjMatrix) % 32 == 0, "Invalid size for ProjMatrix");
// Global Model Parameters
struct GMP : public ElanBase
{
// 08000500
struct {
u32 frac0:5;
u32 exp0:3;
u32 frac1:5;
u32 exp1:3;
float getCoef0() {
return pow(2.f, exp0 - 1.f) * (1 + (float)frac0 / 32);
}
float getCoef1() {
return pow(2.f, exp1 - 1.f) * (1 + (float)frac1 / 32);
}
} gloss;
union {
struct {
u32 d0:1; // diffuse
u32 s0:1; // specular
u32 a0:1; // alpha?
u32 f0:1; // fog?
u32 d1:1;
u32 s1:1;
u32 a1:1;
u32 f1:1;
u32 vol1UsesVol0UV:1;
u32 b0:1; // constant color
u32 b1:1;
u32 e0:1; // environmental mapping
u32 e1:1;
u32 _res:19;
};
u32 full;
} paramSelect;
// (e=env)
// ee000 1111 1111 specular, lambert
// ee110 0000 0000 vertex color
// ee110 1111 1111 constant
// 00000 1111 1111 bump shading?
// seen:
// 00110 1111 1111 (b0 and b1 set)
// 11000 1111 1111 (e0 and e1 set, followed by vtx type2 (vtx only))
// 11110 1111 1111 (everything! except v1uv0, rt66, vtx type2 (vtx only))
// 00110 0000 0000 (b0 and b1, vf4)
// 00000 1010 1010 specular and fog? soul surfer
// 00010 0010 0010 b0, s0 s1 (initd, headlights)
// 00010 1111 1111 2-volume (clubk2k3 road surface)
u32 diffuse0;
u32 specular0;
u32 diffuse1;
u32 specular1;
u32 _reserved;
u32 _reserved0;
u32 tex0;
u32 _reserved1;
u32 pal0;
u32 _reserved2;
u32 tex1;
u32 _reserved3;
u32 pal1;
};
static_assert(sizeof(GMP) % 32 == 0, "Invalid size for GMP");
union HeaderAndNormal
{
struct {
u32 nx:8;
u32 ny:8;
u32 nz:8;
u32 _res:5;
u32 strip:1;
u32 fan:1;
u32 endOfStrip:1;
};
u32 full;
bool isFirstOrSecond() const { return strip == 0 && fan == 0; }
bool isThird() const { return strip == 1 && fan == 1; }
bool isFan() const { return strip == 0 && fan == 1; }
bool isStrip() const { return strip == 1 && fan == 0; }
};
struct N2_VERTEX
{
HeaderAndNormal header;
float x;
float y;
float z;
};
struct Normal
{
float nx;
float ny;
float nz;
u32 _reserved;
};
struct UnpackedUV
{
float u;
float v;
};
struct PackedUV
{
u32 uv0;
u32 uv1;
};
struct PackedRGB
{
u32 argb0;
u32 argb1;
};
struct BumpMap
{
struct {
u8 bumpDegree;
u8 fixedOffset;
u8 _res[2];
} scaleFactor;
// Normal vectors
struct {
int8_t x;
int8_t y;
int8_t z;
u8 _res;
} tangent;
struct {
int8_t x;
int8_t y;
int8_t z;
u8 _res;
} bitangent;
u32 _res;
};
//
// textured, 1 or 2 para
//
struct N2_VERTEX_VU : public N2_VERTEX
{
UnpackedUV uv;
};
//
// textured, 1 or 2 para with unpacked normal
//
struct N2_VERTEX_VNU : public N2_VERTEX
{
Normal normal;
UnpackedUV uv;
};
//
// for colored vertex, 1 para
//
struct N2_VERTEX_VUR : public N2_VERTEX
{
UnpackedUV uv;
PackedRGB rgb;
};
//
// for bumpmapped, 1 para
//
struct N2_VERTEX_VUB : public N2_VERTEX
{
UnpackedUV uv;
BumpMap bump;
};
struct N2_VERTEX_VR : public N2_VERTEX
{
PackedRGB rgb;
};
struct ICHList : public ElanBase
{
enum {
VTX_TYPE_V = 0x00000002,
VTX_TYPE_VU = 0x0000000A,
VTX_TYPE_VNU = 0x0000000E,
VTX_TYPE_VR = 0X00000042,
VTX_TYPE_VUR = 0x0000004A,
VTX_TYPE_VUB = 0x0000010A,
};
// 08000700
ISP_TSP isp;
TSP tsp0;
TCW tcw0;
TSP tsp1;
TCW tcw1;
u32 flags;
u32 vtxCount;
u32 vertexSize() const
{
switch (flags)
{
case VTX_TYPE_V: return sizeof(N2_VERTEX);
case VTX_TYPE_VU: return sizeof(N2_VERTEX_VU);
case VTX_TYPE_VNU: return sizeof(N2_VERTEX_VNU);
case VTX_TYPE_VR: return sizeof(N2_VERTEX_VR);
case VTX_TYPE_VUR: return sizeof(N2_VERTEX_VUR);
case VTX_TYPE_VUB: return sizeof(N2_VERTEX_VUB);
default: return 0;
}
}
};
static_assert(sizeof(ICHList) % 32 == 0, "Invalid size for ICHList");
struct RegisterWait : public ElanBase
{
// 08000e00
u32 offset; // -1
u32 _res; // d, or 1080000d when waiting for ta reg
u32 mask; // 0
u32 _res0[4];
};
static_assert(sizeof(RegisterWait) % 32 == 0, "Invalid size for RegisterWait");
struct Link : public ElanBase
{
// 08000f00
u32 offset;
u32 vramAddress; // for texture DMA xfers, otherwise 09000000
u32 size;
u32 _res0[4];
};
static_assert(sizeof(Link) % 32 == 0, "Invalid size for Link");
constexpr size_t MAX_LIGHTS = 16;
struct LightModel : public ElanBase
{
// 08000400
struct {
u32 zero:4;
u32 lightFlag:1;
u32 useAmbientBase0:1; // When on, ambient color is multiplied with vertex color.
u32 useAmbientOffset0:1;// Otherwise it's added to the diffuse/offset color as is.
u32 useAmbientBase1:1; // Same for volume1
u32 useAmbientOffset1:1;
u32 useBaseOver:1; // diffusion saturated light: overflow ambient+diffuse into specular
u32 _res:2;
u32 bumpId1:4;
u32 bumpId2:4;
u32 _res0:12;
};
u16 diffuseMask0;
u16 specularMask0;
u32 ambientBase0;
u32 ambientOffset0;
u16 diffuseMask1;
u16 specularMask1;
u32 ambientBase1;
u32 ambientOffset1;
bool isDiffuse(int lightId, int volume) const {
if (volume == 0)
return (diffuseMask0 & (1 << lightId)) != 0;
else
return (diffuseMask1 & (1 << lightId)) != 0;
}
bool isSpecular(int lightId, int volume) const {
if (volume == 0)
return (specularMask0 & (1 << lightId)) != 0;
else
return (specularMask1 & (1 << lightId)) != 0;
}
};
// dmode, smode
enum {
// diffuse and specular
N2_LMETHOD_SINGLE_SIDED,
N2_LMETHOD_DOUBLE_SIDED,
N2_LMETHOD_DOUBLE_SIDED_WITH_TOLERANCE,
N2_LMETHOD_SPECIAL_EFFECT,
// diffuse only
N2_LMETHOD_THIN_SURFACE,
N2_LMETHOD_BUMP_MAP
};
// routing
enum {
N2_LFUNC_BASEDIFF_BASESPEC_ADD,
N2_LFUNC_BASEDIFF_OFFSSPEC_ADD,
N2_LFUNC_OFFSDIFF_BASESPEC_ADD,
N2_LFUNC_OFFSDIFF_OFFSSPEC_ADD,
N2_LFUNC_ALPHADIFF_ADD,
N2_LFUNC_ALPHAATTEN_ADD,
N2_LFUNC_FOGDIFF_ADD,
N2_LFUNC_FOGATTENUATION_ADD,
N2_LFUNC_BASEDIFF_BASESPEC_SUB,
N2_LFUNC_BASEDIFF_OFFSSPEC_SUB,
N2_LFUNC_OFFSDIFF_BASESPEC_SUB,
N2_LFUNC_OFFSDIFF_OFFSSPEC_SUB,
N2_LFUNC_ALPHADIFF_SUB,
N2_LFUNC_ALPHAATTEN_SUB,
N2_LFUNC_FOGDIFF_SUB,
N2_LFUNC_FOGATTEN_SUB,
};
struct ParallelLight : public ElanBase
{
// 08100400
struct {
u32 lightId:4;
u32 _res:4;
u32 blue:8;
u32 green:8;
u32 red:8;
};
struct {
u32 dirZ:8;
u32 dirY:8;
u32 dirX:8;
u32 routing:4;
u32 dmode:2;
u32 _res1:2;
};
u32 _res2[5];
float getDirX() const {
return (((int8_t)dirX << 4) | (int)((pcw.full >> 16) & 0xf)) / 2047.f;
}
float getDirY() const {
return (((int8_t)dirY << 4) | (int)((pcw.full >> 4) & 0xf)) / 2047.f;
}
float getDirZ() const {
return (((int8_t)dirZ << 4) | (int)((pcw.full >> 0) & 0xf)) / 2047.f;
}
};
struct PointLight : public ElanBase
{
// 08000400
struct {
u32 lightId:4;
u32 _res:1;
u32 dmode:3;
u32 blue:8;
u32 green:8;
u32 red:8;
};
struct {
u32 dirZ:8;
u32 dirY:8;
u32 dirX:8;
u32 routing:4;
u32 smode:2;
u32 one:1;
u32 dattenmode:1;
};
float posX;
float posY;
float posZ;
u16 _distA;
u16 _distB;
u16 _angleA;
u16 _angleB;
float getDirX() const {
return (((int8_t)dirX << 4) | (int)((pcw.full >> 16) & 0xf)) / 2047.f;
}
float getDirY() const {
return (((int8_t)dirY << 4) | (int)((pcw.full >> 4) & 0xf)) / 2047.f;
}
float getDirZ() const {
return (((int8_t)dirZ << 4) | (int)((pcw.full >> 0) & 0xf)) / 2047.f;
}
static float f16tof32(u16 v)
{
u32 z = v << 16;
return (float&)z;
}
float distA() const { return f16tof32(_distA); }
float distB() const { return f16tof32(_distB); }
float angleA() const { return f16tof32(_angleA); }
float angleB() const { return f16tof32(_angleB); }
float attnMinDistance() const {
return -distB() / (distA() - 1);
}
float attnMaxDistance() const {
return -distB() / distA();
}
float attnDist(float dist) const {
float rv;
if (dattenmode)
rv = distB() * dist + distA();
else
rv = distB() / dist + distA();
return std::max(0.f, std::min(1.f, rv));
}
bool isAttnDist() const {
return distA() != 1 || distB() != 0;
}
bool isAttnAngle() const {
return angleA() != 1 || angleB() != 0;
}
};
}
+7
View File
@@ -24,6 +24,7 @@
#include "rend/TexCache.h"
#include "serialize.h"
#include "pvr_mem.h"
#include "elan.h"
// ta.cpp
extern u8 ta_fsm[2049]; //[2048] stores the current state
@@ -43,17 +44,21 @@ void reset(bool hard)
if (hard)
rend_reset();
tactx_Term();
elan::reset(hard);
ta_parse_reset();
}
void init()
{
spg_Init();
elan::init();
}
void term()
{
tactx_Term();
spg_Term();
elan::term();
}
void serialize(Serializer& ser)
@@ -72,6 +77,7 @@ void serialize(Serializer& ser)
if (!ser.rollback())
ser.serialize(vram.data, vram.size);
elan::serialize(ser);
}
void deserialize(Deserializer& deser)
@@ -135,6 +141,7 @@ void deserialize(Deserializer& deser)
if (!deser.rollback())
deser.deserialize(vram.data, vram.size);
elan::deserialize(deser);
pal_needs_update = true;
}
+105 -1
View File
@@ -3,20 +3,124 @@
#include "Renderer_if.h"
#include "ta.h"
#include "spg.h"
#include <map>
bool pal_needs_update=true;
bool fog_needs_update=true;
u8 pvr_regs[pvr_RegSize];
#define PVR_REG_NAME(r) { r##_addr, #r },
const std::map<u32, const char *> pvr_reg_names = {
PVR_REG_NAME(ID)
PVR_REG_NAME(REVISION)
PVR_REG_NAME(SOFTRESET)
PVR_REG_NAME(STARTRENDER)
PVR_REG_NAME(TEST_SELECT)
PVR_REG_NAME(PARAM_BASE)
PVR_REG_NAME(REGION_BASE)
PVR_REG_NAME(SPAN_SORT_CFG)
PVR_REG_NAME(VO_BORDER_COL)
PVR_REG_NAME(FB_R_CTRL)
PVR_REG_NAME(FB_W_CTRL)
PVR_REG_NAME(FB_W_LINESTRIDE)
PVR_REG_NAME(FB_R_SOF1)
PVR_REG_NAME(FB_R_SOF2)
PVR_REG_NAME(FB_R_SIZE)
PVR_REG_NAME(FB_W_SOF1)
PVR_REG_NAME(FB_W_SOF2)
PVR_REG_NAME(FB_X_CLIP)
PVR_REG_NAME(FB_Y_CLIP)
PVR_REG_NAME(FPU_SHAD_SCALE)
PVR_REG_NAME(FPU_CULL_VAL)
PVR_REG_NAME(FPU_PARAM_CFG)
PVR_REG_NAME(HALF_OFFSET)
PVR_REG_NAME(FPU_PERP_VAL)
PVR_REG_NAME(ISP_BACKGND_D)
PVR_REG_NAME(ISP_BACKGND_T)
PVR_REG_NAME(ISP_FEED_CFG)
PVR_REG_NAME(SDRAM_REFRESH)
PVR_REG_NAME(SDRAM_ARB_CFG)
PVR_REG_NAME(SDRAM_CFG)
PVR_REG_NAME(FOG_COL_RAM)
PVR_REG_NAME(FOG_COL_VERT)
PVR_REG_NAME(FOG_DENSITY)
PVR_REG_NAME(FOG_CLAMP_MAX)
PVR_REG_NAME(FOG_CLAMP_MIN)
PVR_REG_NAME(SPG_TRIGGER_POS)
PVR_REG_NAME(SPG_HBLANK_INT)
PVR_REG_NAME(SPG_VBLANK_INT)
PVR_REG_NAME(SPG_CONTROL)
PVR_REG_NAME(SPG_HBLANK)
PVR_REG_NAME(SPG_LOAD)
PVR_REG_NAME(SPG_VBLANK)
PVR_REG_NAME(SPG_WIDTH)
PVR_REG_NAME(TEXT_CONTROL)
PVR_REG_NAME(VO_CONTROL)
PVR_REG_NAME(VO_STARTX)
PVR_REG_NAME(VO_STARTY)
PVR_REG_NAME(SCALER_CTL)
PVR_REG_NAME(PAL_RAM_CTRL)
PVR_REG_NAME(SPG_STATUS)
PVR_REG_NAME(FB_BURSTCTRL)
PVR_REG_NAME(FB_C_SOF)
PVR_REG_NAME(Y_COEFF)
PVR_REG_NAME(PT_ALPHA_REF)
PVR_REG_NAME(TA_OL_BASE)
PVR_REG_NAME(TA_ISP_BASE)
PVR_REG_NAME(TA_OL_LIMIT)
PVR_REG_NAME(TA_ISP_LIMIT)
PVR_REG_NAME(TA_NEXT_OPB)
PVR_REG_NAME(TA_ITP_CURRENT)
PVR_REG_NAME(TA_GLOB_TILE_CLIP)
PVR_REG_NAME(TA_ALLOC_CTRL)
PVR_REG_NAME(TA_LIST_INIT)
PVR_REG_NAME(TA_YUV_TEX_BASE)
PVR_REG_NAME(TA_YUV_TEX_CTRL)
PVR_REG_NAME(TA_YUV_TEX_CNT)
PVR_REG_NAME(TA_LIST_CONT)
PVR_REG_NAME(TA_NEXT_OPB_INIT)
PVR_REG_NAME(SIGNATURE1)
PVR_REG_NAME(SIGNATURE2)
};
#undef PVR_REG_NAME
static const char *regName(u32 paddr)
{
u32 addr = paddr & pvr_RegMask;
static char regName[32];
auto it = pvr_reg_names.find(addr);
if (it == pvr_reg_names.end())
{
if (addr >= FOG_TABLE_START_addr && addr <= FOG_TABLE_END_addr)
sprintf(regName, "FOG_TABLE[%x]", addr - FOG_TABLE_START_addr);
else if (addr >= TA_OL_POINTERS_START_addr && addr <= TA_OL_POINTERS_END_addr)
sprintf(regName, "TA_OL_POINTERS[%x]", addr - TA_OL_POINTERS_START_addr);
else if (addr >= PALETTE_RAM_START_addr && addr <= PALETTE_RAM_END_addr)
sprintf(regName, "PALETTE[%x]", addr - PALETTE_RAM_START_addr);
else
sprintf(regName, "?%08x", paddr);
return regName;
}
else
return it->second;
}
u32 pvr_ReadReg(u32 addr)
{
if ((addr & pvr_RegMask) != SPG_STATUS_addr)
DEBUG_LOG(PVR, "read %s.%c == %x", regName(addr),
((addr >> 26) & 7) == 2 ? 'b' : (addr & 0x2000000) ? '1' : '0',
PvrReg(addr, u32));
return PvrReg(addr,u32);
}
void pvr_WriteReg(u32 paddr,u32 data)
{
u32 addr = paddr & pvr_RegMask;
DEBUG_LOG(PVR, "write %s.%c = %x", regName(paddr),
((paddr >> 26) & 7) == 2 ? 'b' : (paddr & 0x2000000) ? '1' : '0',
data);
switch (addr)
{
@@ -46,7 +150,7 @@ void pvr_WriteReg(u32 paddr,u32 data)
case TA_LIST_CONT_addr:
//a write of anything works ?
ta_vtx_ListCont();
ta_vtx_ListInit();
break;
case SPG_CONTROL_addr:
+2 -5
View File
@@ -471,7 +471,8 @@ union FOG_DENSITY_type
#define TA_LIST_CONT_addr 0x00000160 // RW TA continuation processing
#define TA_NEXT_OPB_INIT_addr 0x00000164 // RW Additional OPB starting address
#define SIGNATURE1_addr 0x00000180 // ?
#define SIGNATURE2_addr 0x00000184 // ?
#define FOG_TABLE_START_addr 0x00000200 // RW Look-up table Fog data
#define FOG_TABLE_END_addr 0x000003FC
@@ -575,7 +576,3 @@ union FOG_DENSITY_type
#define FOG_TABLE (&PvrReg(FOG_TABLE_START_addr,u32)) // RW Look-up table Fog data
#define TA_OL_POINTERS (&PvrReg(TA_OL_POINTERS_START_addr),u32) // R TA object List Pointer data
#define PALETTE_RAM (&PvrReg(PALETTE_RAM_START_addr,u32)) // RW Palette RAM
#define TA_CURRENT_CTX (TA_ISP_BASE & 0xF00000)
#define CORE_CURRENT_CTX (PARAM_BASE & 0xF00000)
+15 -3
View File
@@ -255,6 +255,9 @@ int spg_line_sched(int tag, int cycl, int jit)
if (lightgun_line != 0xffff && min_scanline < lightgun_line)
min_active = std::min(min_active, lightgun_line);
if (SPG_HBLANK_INT.hblank_int_mode == 0 && min_scanline < SPG_HBLANK_INT.line_comp_val)
min_active = std::min(min_active, SPG_HBLANK_INT.line_comp_val);
min_active = std::max(min_active,min_scanline);
return (min_active - prv_cur_scanline) * Line_Cycles;
@@ -280,9 +283,18 @@ void read_lightgun_position(int x, int y)
int rend_end_sch(int tag, int cycl, int jitt)
{
asic_RaiseInterrupt(holly_RENDER_DONE);
asic_RaiseInterrupt(holly_RENDER_DONE_isp);
asic_RaiseInterrupt(holly_RENDER_DONE_vd);
if (settings.platform.isNaomi2())
{
asic_RaiseInterruptBothCLX(holly_RENDER_DONE);
asic_RaiseInterruptBothCLX(holly_RENDER_DONE_isp);
asic_RaiseInterruptBothCLX(holly_RENDER_DONE_vd);
}
else
{
asic_RaiseInterrupt(holly_RENDER_DONE);
asic_RaiseInterrupt(holly_RENDER_DONE_isp);
asic_RaiseInterrupt(holly_RENDER_DONE_vd);
}
rend_end_render();
return 0;
}
+241 -10
View File
@@ -1,6 +1,7 @@
#include "ta.h"
#include "ta_ctx.h"
#include "hw/holly/holly_intc.h"
#include "pvr_mem.h"
/*
Threaded TA Implementation
@@ -223,7 +224,10 @@ static NOINLINE void DYNACALL ta_handle_cmd(u32 trans)
ta_fsm_cl=dat->pcw.ListType;
//printf("List %d ended\n",ta_fsm_cl);
asic_RaiseInterrupt( ListEndInterrupt[ta_fsm_cl]);
if (settings.platform.isNaomi2())
asic_RaiseInterruptBothCLX(ListEndInterrupt[ta_fsm_cl]);
else
asic_RaiseInterrupt(ListEndInterrupt[ta_fsm_cl]);
ta_fsm_cl=7;
trans=TAS_NS;
}
@@ -259,25 +263,252 @@ static NOINLINE void DYNACALL ta_handle_cmd(u32 trans)
static OnLoad ol_fillfsm(&fill_fsm);
void ta_vtx_ListCont()
{
SetCurrentTARC(TA_CURRENT_CTX);
ta_tad.Continue();
/*
Volume,Col_Type,Texture,Offset,Gouraud,16bit_UV
ta_cur_state=TAS_NS;
ta_fsm_cl = 7;
0 0 0 (0) x invalid Polygon Type 0 Polygon Type 0
0 0 1 x x 0 Polygon Type 0 Polygon Type 3
0 0 1 x x 1 Polygon Type 0 Polygon Type 4
0 1 0 (0) x invalid Polygon Type 0 Polygon Type 1
0 1 1 x x 0 Polygon Type 0 Polygon Type 5
0 1 1 x x 1 Polygon Type 0 Polygon Type 6
0 2 0 (0) x invalid Polygon Type 1 Polygon Type 2
0 2 1 0 x 0 Polygon Type 1 Polygon Type 7
0 2 1 0 x 1 Polygon Type 1 Polygon Type 8
0 2 1 1 x 0 Polygon Type 2 Polygon Type 7
0 2 1 1 x 1 Polygon Type 2 Polygon Type 8
0 3 0 (0) x invalid Polygon Type 0 Polygon Type 2
0 3 1 x x 0 Polygon Type 0 Polygon Type 7
0 3 1 x x 1 Polygon Type 0 Polygon Type 8
1 0 0 (0) x invalid Polygon Type 3 Polygon Type 9
1 0 1 x x 0 Polygon Type 3 Polygon Type 11
1 0 1 x x 1 Polygon Type 3 Polygon Type 12
1 2 0 (0) x invalid Polygon Type 4 Polygon Type 10
1 2 1 x x 0 Polygon Type 4 Polygon Type 13
1 2 1 x x 1 Polygon Type 4 Polygon Type 14
1 3 0 (0) x invalid Polygon Type 3 Polygon Type 10
1 3 1 x x 0 Polygon Type 3 Polygon Type 13
1 3 1 x x 1 Polygon Type 3 Polygon Type 14
Sprites :
(0) (0) 0 (0) (0) invalid Sprite Sprite Type 0
(0) (0) 1 x (0) (1) Sprite Sprite Type 1
*/
//helpers 0-14
u32 TaTypeLut::poly_data_type_id(PCW pcw)
{
if (pcw.Texture)
{
//textured
if (pcw.Volume==0)
{ //single volume
if (pcw.Col_Type==0)
{
if (pcw.UV_16bit==0)
return 3; //(Textured, Packed Color , 32b uv)
else
return 4; //(Textured, Packed Color , 16b uv)
}
else if (pcw.Col_Type==1)
{
if (pcw.UV_16bit==0)
return 5; //(Textured, Floating Color , 32b uv)
else
return 6; //(Textured, Floating Color , 16b uv)
}
else
{
if (pcw.UV_16bit==0)
return 7; //(Textured, Intensity , 32b uv)
else
return 8; //(Textured, Intensity , 16b uv)
}
}
else
{
//two volumes
if (pcw.Col_Type==0)
{
if (pcw.UV_16bit==0)
return 11; //(Textured, Packed Color, with Two Volumes)
else
return 12; //(Textured, Packed Color, 16bit UV, with Two Volumes)
}
else if (pcw.Col_Type==1)
{
//die ("invalid");
return 0xFFFFFFFF;
}
else
{
if (pcw.UV_16bit==0)
return 13; //(Textured, Intensity, with Two Volumes)
else
return 14; //(Textured, Intensity, 16bit UV, with Two Volumes)
}
}
}
else
{
//non textured
if (pcw.Volume==0)
{ //single volume
if (pcw.Col_Type==0)
return 0; //(Non-Textured, Packed Color)
else if (pcw.Col_Type==1)
return 1; //(Non-Textured, Floating Color)
else
return 2; //(Non-Textured, Intensity)
}
else
{
//two volumes
if (pcw.Col_Type==0)
return 9; //(Non-Textured, Packed Color, with Two Volumes)
else if (pcw.Col_Type==1)
{
//die ("invalid");
return 0xFFFFFFFF;
}
else
{
return 10; //(Non-Textured, Intensity, with Two Volumes)
}
}
}
}
//0-4 | 0x80
u32 TaTypeLut::poly_header_type_size(PCW pcw)
{
if (pcw.Volume == 0)
{
if ( pcw.Col_Type<2 ) //0,1
{
return 0 | 0; //Polygon Type 0 -- SZ32
}
else if ( pcw.Col_Type == 2 )
{
if (pcw.Texture)
{
if (pcw.Offset)
{
return 2 | 0x80; //Polygon Type 2 -- SZ64
}
else
{
return 1 | 0; //Polygon Type 1 -- SZ32
}
}
else
{
return 1 | 0; //Polygon Type 1 -- SZ32
}
}
else //col_type ==3
{
return 0 | 0; //Polygon Type 0 -- SZ32
}
}
else
{
if ( pcw.Col_Type==0 ) //0
{
return 3 | 0; //Polygon Type 3 -- SZ32
}
else if ( pcw.Col_Type==2 ) //2
{
return 4 | 0x80; //Polygon Type 4 -- SZ64
}
else if ( pcw.Col_Type==3 ) //3
{
return 3 | 0; //Polygon Type 3 -- SZ32
}
else
{
return 0xFFDDEEAA;//die ("data->pcw.Col_Type==1 && volume ==1");
}
}
}
TaTypeLut::TaTypeLut()
{
for (int i = 0; i < 256; i++)
{
PCW pcw;
pcw.obj_ctrl = i;
u32 rv = poly_data_type_id(pcw);
u32 type = poly_header_type_size(pcw);
if (type & 0x80)
rv |= SZ64 << 30;
else
rv |= SZ32 << 30;
rv |= (type & 0x7F) << 8;
table[i] = rv;
}
}
static u32 opbSize(int n)
{
return n == 0 ? 0 : 16 << n;
}
static void markObjectListBlocks()
{
u32 addr = TA_OL_BASE;
// opaque
u32 opBlockSize = opbSize(TA_ALLOC_CTRL & 3);
if (opBlockSize == 0)
{
// skip modvols OPBs
addr += opbSize((TA_ALLOC_CTRL >> 4) & 3) * (TA_GLOB_TILE_CLIP.tile_y_num + 1) * (TA_GLOB_TILE_CLIP.tile_x_num + 1);
// transparent
opBlockSize = opbSize((TA_ALLOC_CTRL >> 8) & 3);
if (opBlockSize == 0)
{
// skip TR modvols OPBs
addr += opbSize((TA_ALLOC_CTRL >> 12) & 3) * (TA_GLOB_TILE_CLIP.tile_y_num + 1) * (TA_GLOB_TILE_CLIP.tile_x_num + 1);
// punch-through
opBlockSize = opbSize((TA_ALLOC_CTRL >> 16) & 3);
if (opBlockSize == 0)
return;
}
}
for (int y = 0; y <= TA_GLOB_TILE_CLIP.tile_y_num; y++)
for (int x = 0; x <= TA_GLOB_TILE_CLIP.tile_x_num; x++)
{
pvr_write32p(addr, TA_OL_BASE);
addr += opBlockSize;
}
}
void ta_vtx_ListInit()
{
SetCurrentTARC(TA_CURRENT_CTX);
SetCurrentTARC(TA_OL_BASE);
ta_tad.ClearPartial();
markObjectListBlocks();
ta_cur_state=TAS_NS;
ta_cur_state = TAS_NS;
ta_fsm_cl = 7;
if (settings.platform.isNaomi2())
ta_parse_reset();
}
void ta_vtx_SoftReset()
{
ta_cur_state=TAS_NS;
ta_cur_state = TAS_NS;
}
static INLINE
+6 -2
View File
@@ -3,16 +3,18 @@
#include "ta_ctx.h"
#include "hw/sh4/sh4_if.h"
constexpr u32 SZ32 = 1;
constexpr u32 SZ64 = 2;
struct TA_context;
void ta_vtx_ListCont();
void ta_vtx_ListInit();
void ta_vtx_SoftReset();
void DYNACALL ta_vtx_data32(const SQBuffer *data);
void ta_vtx_data(const SQBuffer *data, u32 size);
bool ta_parse_vdrc(TA_context *ctx, bool bgraColors = false);
bool ta_parse(TA_context *ctx);
class TaTypeLut
{
@@ -25,4 +27,6 @@ public:
private:
TaTypeLut();
u32 poly_data_type_id(PCW pcw);
u32 poly_header_type_size(PCW pcw);
};
+77 -77
View File
@@ -11,8 +11,8 @@ static int RenderCount;
TA_context* ta_ctx;
tad_context ta_tad;
TA_context* vd_ctx;
rend_context vd_rc;
static void tactx_Recycle(TA_context* ctx);
static TA_context *tactx_Find(u32 addr, bool allocnew = false);
void SetCurrentTARC(u32 addr)
{
@@ -106,62 +106,58 @@ static std::mutex mtx_pool;
static std::vector<TA_context*> ctx_pool;
static std::vector<TA_context*> ctx_list;
TA_context* tactx_Alloc()
TA_context *tactx_Alloc()
{
TA_context* rv = 0;
TA_context *ctx = nullptr;
mtx_pool.lock();
if (!ctx_pool.empty())
{
rv = ctx_pool[ctx_pool.size()-1];
ctx = ctx_pool.back();
ctx_pool.pop_back();
}
mtx_pool.unlock();
if (!rv)
{
rv = new TA_context();
rv->Alloc();
}
return rv;
if (ctx == nullptr)
{
ctx = new TA_context();
ctx->Alloc();
}
return ctx;
}
void tactx_Recycle(TA_context* poped_ctx)
static void tactx_Recycle(TA_context* ctx)
{
if (ctx->nextContext != nullptr)
tactx_Recycle(ctx->nextContext);
mtx_pool.lock();
if (ctx_pool.size() > 3)
{
if (ctx_pool.size()>2)
{
poped_ctx->Free();
delete poped_ctx;
}
else
{
poped_ctx->Reset();
ctx_pool.push_back(poped_ctx);
}
delete ctx;
}
else
{
ctx->Reset();
ctx_pool.push_back(ctx);
}
mtx_pool.unlock();
}
TA_context* tactx_Find(u32 addr, bool allocnew)
static TA_context *tactx_Find(u32 addr, bool allocnew)
{
for (size_t i=0; i<ctx_list.size(); i++)
{
if (ctx_list[i]->Address==addr)
return ctx_list[i];
}
for (TA_context *ctx : ctx_list)
if (ctx->Address == addr)
return ctx;
if (allocnew)
{
TA_context* rv = tactx_Alloc();
rv->Address=addr;
ctx_list.push_back(rv);
TA_context *ctx = tactx_Alloc();
ctx->Address = addr;
ctx_list.push_back(ctx);
return rv;
return ctx;
}
return 0;
return nullptr;
}
TA_context* tactx_Pop(u32 addr)
@@ -188,20 +184,13 @@ void tactx_Term()
if (ta_ctx != nullptr)
SetCurrentTARC(TACTX_NONE);
for (size_t i = 0; i < ctx_list.size(); i++)
{
ctx_list[i]->Free();
delete ctx_list[i];
}
for (TA_context *ctx : ctx_list)
delete ctx;
ctx_list.clear();
mtx_pool.lock();
{
for (size_t i = 0; i < ctx_pool.size(); i++)
{
ctx_pool[i]->Free();
delete ctx_pool[i];
}
}
for (TA_context *ctx : ctx_pool)
delete ctx;
ctx_pool.clear();
mtx_pool.unlock();
}
@@ -212,8 +201,8 @@ static void serializeContext(Serializer& ser, const TA_context *ctx)
{
if (ser.dryrun())
{
// Maximum size: address, size, data, render pass count, render passes
ser.skip(4 + 4 + TA_DATA_SIZE + 4 + ARRAY_SIZE(tad_context::render_passes) * 4);
// Maximum size: address, size, data
ser.skip(4 + 4 + TA_DATA_SIZE);
return;
}
if (ctx == nullptr)
@@ -226,12 +215,6 @@ static void serializeContext(Serializer& ser, const TA_context *ctx)
const u32 taSize = tad.thd_data - tad.thd_root;
ser << taSize;
ser.serialize(tad.thd_root, taSize);
ser << tad.render_pass_count;
for (u32 i = 0; i < tad.render_pass_count; i++)
{
u32 offset = (u32)(tad.render_passes[i] - tad.thd_root);
ser << offset;
}
}
static void deserializeContext(Deserializer& deser, TA_context **pctx)
@@ -249,39 +232,56 @@ static void deserializeContext(Deserializer& deser, TA_context **pctx)
tad_context& tad = (*pctx)->tad;
deser.deserialize(tad.thd_root, size);
tad.thd_data = tad.thd_root + size;
if (deser.version() >= Deserializer::V12 || (deser.version() >= Deserializer::V12_LIBRETRO && deser.version() < Deserializer::V5))
if ((deser.version() >= Deserializer::V12 && deser.version() < Deserializer::V26)
|| (deser.version() >= Deserializer::V12_LIBRETRO && deser.version() < Deserializer::V5))
{
deser >> tad.render_pass_count;
for (u32 i = 0; i < tad.render_pass_count; i++)
{
u32 offset;
deser >> offset;
tad.render_passes[i] = tad.thd_root + offset;
}
}
else
{
tad.render_pass_count = 0;
u32 render_pass_count;
deser >> render_pass_count;
deser.skip(sizeof(u32) * render_pass_count);
}
}
void SerializeTAContext(Serializer& ser)
{
serializeContext(ser, ta_ctx);
if (TA_CURRENT_CTX != CORE_CURRENT_CTX)
serializeContext(ser, tactx_Find(TA_CURRENT_CTX, false));
else
serializeContext(ser, nullptr);
ser << (u32)ctx_list.size();
int curCtx = -1;
for (const auto& ctx : ctx_list)
{
if (ctx == ::ta_ctx)
curCtx = (int)(&ctx - &ctx_list[0]);
serializeContext(ser, ctx);
}
ser << curCtx;
}
void DeserializeTAContext(Deserializer& deser)
{
if (::ta_ctx != nullptr)
SetCurrentTARC(TACTX_NONE);
TA_context *ta_cur_ctx;
deserializeContext(deser, &ta_cur_ctx);
if (ta_cur_ctx != nullptr)
SetCurrentTARC(ta_cur_ctx->Address);
if (deser.version() >= Deserializer::V20)
if (deser.version() >= Deserializer::V25)
{
u32 listSize;
deser >> listSize;
for (const auto& ctx : ctx_list)
tactx_Recycle(ctx);
ctx_list.clear();
for (u32 i = 0; i < listSize; i++)
{
TA_context *ctx;
deserializeContext(deser, &ctx);
}
int curCtx;
deser >> curCtx;
if (curCtx != -1)
SetCurrentTARC(ctx_list[curCtx]->Address);
}
else
{
TA_context *ta_cur_ctx;
deserializeContext(deser, &ta_cur_ctx);
if (ta_cur_ctx != nullptr)
SetCurrentTARC(ta_cur_ctx->Address);
if (deser.version() >= Deserializer::V20)
deserializeContext(deser, &ta_cur_ctx);
}
}
+173 -43
View File
@@ -9,6 +9,7 @@
#include <mutex>
class BaseTextureCacheData;
struct N2LightModel;
//Vertex storage types
struct Vertex
@@ -25,6 +26,9 @@ struct Vertex
u8 spc1[4];
float u1,v1;
// Naomi2 normal
float nx,ny,nz;
};
struct PolyParam
@@ -33,9 +37,6 @@ struct PolyParam
u32 count;
BaseTextureCacheData *texture;
#if !defined(HOST_64BIT_CPU)
u32 _pad0;
#endif
TSP tsp;
TCW tcw;
@@ -47,9 +48,64 @@ struct PolyParam
TSP tsp1;
TCW tcw1;
BaseTextureCacheData *texture1;
#if !defined(HOST_64BIT_CPU)
u32 _pad1;
#endif
const float *mvMatrix;
const float *normalMatrix;
const float *projMatrix;
float glossCoef[2];
const N2LightModel *lightModel;
bool envMapping[2];
bool constantColor[2];
void init()
{
first = 0;
count = 0;
texture = nullptr;
tsp.full = 0;
tcw.full = 0;
pcw.full = 0;
isp.full = 0;
zvZ = 0;
tileclip = 0;
tsp1.full = -1;
tcw1.full = -1;
texture1 = nullptr;
mvMatrix = nullptr;
normalMatrix = nullptr;
projMatrix = nullptr;
glossCoef[0] = 0;
glossCoef[1] = 0;
lightModel = nullptr;
envMapping[0] = false;
envMapping[1] = false;
constantColor[0] = false;
constantColor[1] = false;
}
bool equivalentIgnoreCullingDirection(const PolyParam& other) const
{
return ((pcw.full ^ other.pcw.full) & 0x300CE) == 0
&& ((isp.full ^ other.isp.full) & 0xF4000000) == 0
&& tcw.full == other.tcw.full
&& tsp.full == other.tsp.full
&& tileclip == other.tileclip
&& tcw1.full == other.tcw1.full
&& tsp1.full == other.tsp1.full
&& mvMatrix == other.mvMatrix
&& normalMatrix == other.normalMatrix
&& projMatrix == other.projMatrix
&& glossCoef[0] == other.glossCoef[0]
&& glossCoef[1] == other.glossCoef[1]
&& lightModel == other.lightModel
&& envMapping[0] == other.envMapping[0]
&& constantColor[0] == other.constantColor[0]
&& envMapping[1] == other.envMapping[1]
&& constantColor[1] == other.constantColor[1];
}
bool isNaomi2() const { return projMatrix != nullptr; }
};
struct ModifierVolumeParam
@@ -57,6 +113,20 @@ struct ModifierVolumeParam
u32 first;
u32 count;
ISP_Modvol isp;
const float *mvMatrix;
const float *projMatrix;
void init()
{
first = 0;
count = 0;
isp.full = 0;
mvMatrix = nullptr;
projMatrix = nullptr;
}
bool isNaomi2() const { return projMatrix != nullptr; }
};
struct ModTriangle
@@ -64,18 +134,17 @@ struct ModTriangle
f32 x0,y0,z0,x1,y1,z1,x2,y2,z2;
};
constexpr size_t MAX_PASSES = 10;
struct tad_context
{
u8* thd_data;
u8* thd_root;
u8* thd_old_data;
u8 *render_passes[10];
u32 render_pass_count;
void Clear()
{
thd_old_data = thd_data = thd_root;
render_pass_count = 0;
}
void ClearPartial()
@@ -84,13 +153,6 @@ struct tad_context
thd_data = thd_root;
}
void Continue()
{
render_passes[render_pass_count] = End();
if (render_pass_count < sizeof(render_passes) / sizeof(u8*) - 1)
render_pass_count++;
}
u8* End()
{
return thd_data == thd_root ? thd_old_data : thd_data;
@@ -98,10 +160,9 @@ struct tad_context
void Reset(u8* ptr)
{
thd_data = thd_root = thd_old_data = ptr;
render_pass_count = 0;
thd_root = ptr;
Clear();
}
};
struct RenderPass {
@@ -114,6 +175,48 @@ struct RenderPass {
u32 mvo_tr_count;
};
struct N2Matrix
{
float mat[16];
};
struct N2Light
{
float color[4];
float direction[4]; // For parallel/spot
float position[4]; // For spot/point
int parallel;
int routing;
int dmode;
int smode;
int diffuse[2];
int specular[2];
float attnDistA;
float attnDistB;
float attnAngleA; // For spot
float attnAngleB;
int distAttnMode; // For spot/point
int _pad[3];
};
struct N2LightModel
{
N2Light lights[16];
float ambientBase[2][4]; // base ambient colors
float ambientOffset[2][4]; // offset ambient colors
int ambientMaterialBase[2]; // base ambient light is multiplied by model material/color
int ambientMaterialOffset[2];// offset ambient light is multiplied by model material/color
int lightCount;
int useBaseOver; // base color overflows into offset color
int bumpId1; // Light index for vol0 bump mapping
int bumpId2; // Light index for vol1 bump mapping
};
struct rend_context
{
u8* proc_start;
@@ -129,6 +232,8 @@ struct rend_context
FB_X_CLIP_type fb_X_CLIP;
FB_Y_CLIP_type fb_Y_CLIP;
u32 fb_W_LINESTRIDE;
u32 fb_W_SOF1;
FB_W_CTRL_type fb_W_CTRL;
RGBAColor fog_clamp_min;
RGBAColor fog_clamp_max;
@@ -144,6 +249,9 @@ struct rend_context
List<PolyParam> global_param_tr;
List<RenderPass> render_passes;
List<N2Matrix> matrices;
List<N2LightModel> lightModels;
void Clear()
{
verts.Clear();
@@ -156,12 +264,20 @@ struct rend_context
global_param_mvo_tr.Clear();
render_passes.Clear();
Overrun=false;
fZ_min= 1000000.0f;
fZ_max= 1.0f;
// Reserve space for background poly
global_param_op.Append()->init();
verts.Append(4);
Overrun = false;
fZ_min = 1000000.0f;
fZ_max = 1.0f;
isRenderFramebuffer = false;
matrices.Clear();
lightModels.Clear();
}
void newRenderPass();
u32 getFramebufferWidth() const {
u32 w = fb_X_CLIP.max + 1;
if (fb_W_LINESTRIDE != 0)
@@ -180,15 +296,13 @@ struct rend_context
struct TA_context
{
u32 Address;
u32 LastUsed;
std::mutex thd_inuse;
std::mutex rend_inuse;
tad_context tad;
rend_context rend;
TA_context *nextContext = nullptr;
/*
Dreamcast games use up to 20k vtx, 30k idx, 1k (in total) parameters.
at 30 fps, thats 600kvtx (900 stripped)
@@ -205,20 +319,18 @@ struct TA_context
sa2: idx: 36094, vtx: 24520, op: 1330, pt: 10, tr: 177, mvo: 39, modt: 360, ov: 0
*/
void MarkRend(u32 render_pass)
void MarkRend()
{
verify(render_pass <= tad.render_pass_count);
rend.proc_start = render_pass == 0 ? tad.thd_root : tad.render_passes[render_pass - 1];
rend.proc_end = render_pass == tad.render_pass_count ? tad.End() : tad.render_passes[render_pass];
rend.proc_start = tad.thd_root;
rend.proc_end = tad.End();
}
void Alloc()
{
tad.Reset((u8*)allocAligned(32, TA_DATA_SIZE));
rend.verts.InitBytes(4 * 1024 * 1024, &rend.Overrun, "verts"); //up to 4 mb of vtx data/frame = ~ 96k vtx/frame
rend.idx.Init(120 * 1024, &rend.Overrun, "idx"); //up to 120K indexes ( idx have stripification overhead )
rend.verts.Init(320 * 1024, &rend.Overrun, "verts");
rend.idx.Init(320 * 1024, &rend.Overrun, "idx");
rend.global_param_op.Init(16384, &rend.Overrun, "global_param_op");
rend.global_param_pt.Init(5120, &rend.Overrun, "global_param_pt");
rend.global_param_mvo.Init(4096, &rend.Overrun, "global_param_mvo");
@@ -227,7 +339,9 @@ struct TA_context
rend.modtrig.Init(16384, &rend.Overrun, "modtrig");
rend.render_passes.Init(sizeof(RenderPass) * 10, &rend.Overrun, "render_passes"); // 10 render passes
rend.render_passes.Init(sizeof(RenderPass) * MAX_PASSES, &rend.Overrun, "render_passes"); // 10 render passes
rend.matrices.Init(2000, &rend.Overrun, "matrices");
rend.lightModels.Init(150, &rend.Overrun, "lightModels");
Reset();
}
@@ -236,13 +350,14 @@ struct TA_context
{
verify(tad.End() - tad.thd_root <= TA_DATA_SIZE);
tad.Clear();
nextContext = nullptr;
rend_inuse.lock();
rend.Clear();
rend.proc_end = rend.proc_start = tad.thd_root;
rend_inuse.unlock();
}
void Free()
~TA_context()
{
verify(tad.End() - tad.thd_root <= TA_DATA_SIZE);
freeAligned(tad.thd_root);
@@ -255,22 +370,18 @@ struct TA_context
rend.global_param_mvo.Free();
rend.global_param_mvo_tr.Free();
rend.render_passes.Free();
rend.matrices.Free();
rend.lightModels.Free();
}
};
extern TA_context* ta_ctx;
extern tad_context ta_tad;
extern TA_context* vd_ctx;
extern rend_context vd_rc;
TA_context* tactx_Find(u32 addr, bool allocnew=false);
TA_context* tactx_Pop(u32 addr);
TA_context* tactx_Alloc();
void tactx_Recycle(TA_context* poped_ctx);
void tactx_Term();
TA_context *tactx_Alloc();
/*
Ta Context
@@ -286,7 +397,26 @@ void FinishRender(TA_context* ctx);
//must be moved to proper header
void FillBGP(TA_context* ctx);
bool UsingAutoSort(int pass_number);
bool rend_framePending();
void SerializeTAContext(Serializer& ser);
void DeserializeTAContext(Deserializer& deser);
void ta_add_poly(const PolyParam& pp);
void ta_add_poly(int listType, const ModifierVolumeParam& mvp);
void ta_add_vertex(const Vertex& vtx);
void ta_add_triangle(const ModTriangle& tri);
float* ta_add_matrix(const float *matrix);
N2LightModel *ta_add_light(const N2LightModel& light);
u32 ta_add_ta_data(u32 *data, u32 size);
int getTAContextAddresses(u32 *addresses);
u32 ta_get_tileclip();
void ta_set_tileclip(u32 tileclip);
u32 ta_get_list_type();
void ta_set_list_type(u32 listType);
void ta_parse_reset();
class TAParserException : public FlycastException
{
public:
TAParserException() : FlycastException("") {}
};
-12
View File
@@ -1,11 +1,6 @@
//structs were getting tooo many , so i moved em here !
#pragma once
#include "types.h"
//bits that affect drawing (for caching params)
#define PCW_DRAW_MASK (0x000000CE)
#pragma pack(push, 1) // n = 1
// Global Param/misc structs
//4B
@@ -37,13 +32,6 @@ union PCW
u32 ParaType : 3;
};
u8 obj_ctrl;
struct
{
u32 padin : 8;
u32 S6X : 1; //set by TA preprocessing if sz64
u32 padin2 : 19;
u32 PTEOS : 4;
};
u32 full;
};
+584 -573
View File
File diff suppressed because it is too large. Load diff
+1 -4
View File
@@ -112,10 +112,7 @@ struct shil_param
bool is_r32() const { return is_r32i() || is_r32f(); }
bool is_r64() const { return is_r64f(); } //just here for symmetry ...
bool is_imm_s8() const { return is_imm() && is_s8(_imm); }
bool is_imm_u8() const { return is_imm() && is_u8(_imm); }
bool is_imm_s16() const { return is_imm() && is_s16(_imm); }
bool is_imm_u16() const { return is_imm() && is_u16(_imm); }
bool is_imm_s8() const { return is_imm() && (int8_t)_imm == (int32_t)_imm; }
u32* reg_ptr() const { verify(is_reg()); return GetRegPtr(_reg); }
s32 reg_nofs() const { verify(is_reg()); return (s32)((u8*)GetRegPtr(_reg) - (u8*)GetRegPtr(reg_xf_0)-sizeof(Sh4cntx)); }
+3 -3
View File
@@ -12,7 +12,7 @@ BSC_PDTRA_type BSC_PDTRA;
void write_BSC_PCTRA(u32 addr, u32 data)
{
BSC_PCTRA.full = data;
if (settings.platform.system == DC_PLATFORM_NAOMI)
if (settings.platform.isNaomi())
NaomiBoardIDWriteControl((u16)data);
//else
//printf("C:BSC_PCTRA = %08X\n",data);
@@ -23,13 +23,13 @@ void write_BSC_PDTRA(u32 addr, u32 data)
BSC_PDTRA.full=(u16)data;
//printf("D:BSC_PDTRA = %04x\n", (u16)data);
if (settings.platform.system == DC_PLATFORM_NAOMI)
if (settings.platform.isNaomi())
NaomiBoardIDWrite((u16)data);
}
u32 read_BSC_PDTRA(u32 addr)
{
if (settings.platform.system == DC_PLATFORM_NAOMI)
if (settings.platform.isNaomi())
{
return NaomiBoardIDRead();
}
+13 -1
View File
@@ -20,9 +20,21 @@ void intc_init();
void intc_reset();
void intc_term();
struct SerialPipe
{
// Serial TX
virtual void write(u8 data) = 0;
// RX buffer Size
virtual int available() = 0;
// Serial RX
virtual u8 read() = 0;
virtual ~SerialPipe() = default;
};
void serial_init();
void serial_reset();
void serial_reset(bool hard);
void serial_term();
void serial_setPipe(SerialPipe *pipe);
void ubc_init();
void ubc_reset();
+91 -37
View File
@@ -15,8 +15,9 @@
#include "hw/sh4/sh4_mmr.h"
#include "hw/sh4/sh4_interrupts.h"
#include "cfg/option.h"
#include "modules.h"
static int tty = 1; // stdout by default
static SerialPipe *serialPipe;
SCIF_SCFSR2_type SCIF_SCFSR2;
SCIF_SCSCR2_type SCIF_SCSCR2;
@@ -66,8 +67,9 @@ static void Serial_UpdateInterrupts()
static void SerialWrite(u32 addr, u32 data)
{
if (config::SerialConsole)
write(tty, &data, 1);
//DEBUG_LOG(COMMON, "serial %02x", data);
if (serialPipe != nullptr)
serialPipe->write(data);
SCIF_SCFSR2.TDFE = 1;
SCIF_SCFSR2.TEND = 1;
@@ -78,18 +80,17 @@ static void SerialWrite(u32 addr, u32 data)
//SCIF_SCFSR2 read
static u32 ReadSerialStatus(u32 addr)
{
#if defined(__unix__) || defined(__APPLE__)
int count = 0;
if (config::SerialConsole && tty != 1
&& ioctl(tty, FIONREAD, &count) == 0 && count > 0)
if (serialPipe != nullptr)
{
return SCIF_SCFSR2.full | 2;
}
else
#endif
{
return SCIF_SCFSR2.full | 0;
constexpr int trigLevels[] { 1, 4, 8, 14 };
int avail = serialPipe->available();
if (avail >= trigLevels[SCIF_SCFCR2.RTRG1 * 2 + SCIF_SCFCR2.RTRG0])
return SCIF_SCFSR2.full | 3; // RDF | DR
else if (avail >= 1)
return SCIF_SCFSR2.full | 1; // DR
}
return SCIF_SCFSR2.full;
}
static void WriteSerialStatus(u32 addr,u32 data)
@@ -108,14 +109,19 @@ static void WriteSerialStatus(u32 addr,u32 data)
//SCIF_SCFDR2 - 16b
static u32 Read_SCFDR2(u32 addr)
{
return 0;
if (serialPipe != nullptr && serialPipe->available() > 0)
return 1; // TODO more?
else
return 0;
}
//SCIF_SCFRDR2
static u32 ReadSerialData(u32 addr)
{
u8 data = 0;
if (tty != 1)
read(tty, &data, 1);
if (serialPipe != nullptr)
data = serialPipe->read();
return data;
}
@@ -133,6 +139,65 @@ static void SCSCR2_write(u32 addr, u32 data)
Serial_UpdateInterrupts();
}
struct PTYPipe : public SerialPipe
{
void write(u8 data) override {
if (config::SerialConsole)
::write(tty, &data, 1);
}
int available() override {
int count = 0;
#if defined(__unix__) || defined(__APPLE__)
if (config::SerialConsole && tty != 1)
ioctl(tty, FIONREAD, &count);
#endif
return count;
}
u8 read() override {
u8 data = 0;
if (tty != 1)
::read(tty, &data, 1);
return data;
}
void init()
{
#if defined(__unix__) || defined(__APPLE__)
if (config::SerialConsole && config::SerialPTY && tty == 1)
{
tty = open("/dev/ptmx", O_RDWR | O_NDELAY | O_NOCTTY | O_NONBLOCK);
if (tty < 0)
{
ERROR_LOG(BOOT, "Cannot open /dev/ptmx: errno %d", errno);
tty = 1;
}
else
{
grantpt(tty);
unlockpt(tty);
NOTICE_LOG(BOOT, "Pseudoterminal is at %s", ptsname(tty));
}
}
#endif
serial_setPipe(this);
}
void term()
{
if (tty != 1)
{
::close(tty);
tty = 1;
}
}
private:
int tty = 1;
};
static PTYPipe ptyPipe;
//Init term res
void serial_init()
{
@@ -171,21 +236,6 @@ void serial_init()
//SCIF SCLSR2 0xFFE80024 0x1FE80024 16 0x0000 0x0000 Held Held Pclk
sh4_rio_reg(SCIF,SCIF_SCLSR2_addr,RIO_DATA,16);
#if defined(__unix__) || defined(__APPLE__)
if (config::SerialConsole && config::SerialPTY)
{
tty = open("/dev/ptmx", O_RDWR | O_NDELAY | O_NOCTTY | O_NONBLOCK);
if (tty < 0)
ERROR_LOG(BOOT, "Cannot open /dev/ptmx: errno %d", errno);
else
{
grantpt(tty);
unlockpt(tty);
NOTICE_LOG(BOOT, "Pseudoterminal is at %s", ptsname(tty));
}
}
#endif
// Serial Communication Interface
sh4_rio_reg(SCI, SCI_SCSMR1_addr, RIO_DATA, 8);
sh4_rio_reg(SCI, SCI_SCBRR1_addr, RIO_DATA, 8);
@@ -195,7 +245,8 @@ void serial_init()
sh4_rio_reg(SCI, SCI_SCRDR1_addr, RIO_RO, 8);
sh4_rio_reg(SCI, SCI_SCSPTR1_addr, RIO_DATA, 8);
}
void serial_reset()
void serial_reset(bool hard)
{
/*
SCIF SCSMR2 H'FFE8 0000 H'1FE8 0000 16 H'0000 H'0000 Held Held Pclk
@@ -224,14 +275,17 @@ void serial_reset()
SCI_SCSSR1 = 0x84;
SCI_SCRDR1 = 0;
SCI_SCSPTR1 = 0;
if (hard)
ptyPipe.init();
}
void serial_term()
{
if (tty > 2)
{
close(tty);
tty = 1;
}
ptyPipe.term();
}
void serial_setPipe(SerialPipe *pipe)
{
serialPipe = pipe;
}
+8 -13
View File
@@ -7,6 +7,7 @@
#include "sh4_mem.h"
#include "hw/holly/sb_mem.h"
#include "sh4_mmr.h"
#include "hw/pvr/elan.h"
#include "hw/pvr/pvr_mem.h"
#include "hw/sh4/sh4_core.h"
#include "hw/mem/_vmem.h"
@@ -50,14 +51,7 @@ static void map_area1(u32 base)
_vmem_mirror_mapping(0x06 | base, 0x04 | base, 0x02);
}
//AREA 2
static void map_area2_init()
{
}
static void map_area2(u32 base)
{
}
//AREA 2: Naomi2 elan
//AREA 3
static void map_area3_init()
@@ -96,14 +90,15 @@ static void map_area4(u32 base)
template <class T>
T DYNACALL ReadMem_extdev_T(u32 addr)
{
return (T)libExtDevice_ReadMem_A5(addr, sizeof(T));
INFO_LOG(SH4, "Read ext. device (Area 5) undefined @ %08x", addr);
return (T)0;
}
//Write Ext.Device
template <class T>
void DYNACALL WriteMem_extdev_T(u32 addr,T data)
{
libExtDevice_WriteMem_A5(addr, data, sizeof(T));
INFO_LOG(SH4, "Write ext. device (Area 5) undefined @ %08x: %x", addr, (u32)data);
}
_vmem_handler area5_handler;
@@ -152,7 +147,7 @@ void mem_map_default()
//Init Memmaps (register handlers)
map_area0_init();
map_area1_init();
map_area2_init();
elan::vmem_init();
map_area3_init();
map_area4_init();
map_area5_init();
@@ -164,7 +159,7 @@ void mem_map_default()
{
map_area0(i << 5); //Bios,Flahsrom,i/f regs,Ext. Device,Sound Ram
map_area1(i << 5); //VRAM
map_area2(i << 5); //Unassigned
elan::vmem_map(i << 5); // Naomi2 Elan
map_area3(i << 5); //RAM
map_area4(i << 5); //TA
map_area5(i << 5); //Ext. Device
@@ -195,7 +190,7 @@ void mem_Reset(bool hard)
//Reset registers
sh4_area0_Reset(hard);
sh4_mmr_reset(true);
sh4_mmr_reset(hard);
}
void mem_Term()
+25 -27
View File
@@ -781,39 +781,37 @@ void sh4_mmr_init()
void sh4_mmr_reset(bool hard)
{
if (hard)
{
for (auto& reg : CCN)
reg.reset();
for (auto& reg : UBC)
reg.reset();
for (auto& reg : BSC)
reg.reset();
for (auto& reg : DMAC)
reg.reset();
for (auto& reg : CPG)
reg.reset();
for (auto& reg : RTC)
reg.reset();
for (auto& reg : INTC)
reg.reset();
for (auto& reg : TMU)
reg.reset();
for (auto& reg : SCI)
reg.reset();
for (auto& reg : SCIF)
reg.reset();
}
for (auto& reg : CCN)
reg.reset();
for (auto& reg : UBC)
reg.reset();
for (auto& reg : BSC)
reg.reset();
for (auto& reg : DMAC)
reg.reset();
for (auto& reg : CPG)
reg.reset();
for (auto& reg : RTC)
reg.reset();
for (auto& reg : INTC)
reg.reset();
for (auto& reg : TMU)
reg.reset();
for (auto& reg : SCI)
reg.reset();
for (auto& reg : SCIF)
reg.reset();
OnChipRAM = {};
//Reset register values
bsc_reset(hard);
ccn_reset(hard);
bsc_reset(true);
ccn_reset(true);
cpg_reset();
dmac_reset();
intc_reset();
rtc_reset();
serial_reset();
tmu_reset(hard);
serial_reset(hard);
tmu_reset(true);
ubc_reset();
MMU_reset();
+2 -1
View File
@@ -1,7 +1,8 @@
#pragma once
#include <array>
#include "types.h"
#include "../sh4/sh4_if.h"
#include "sh4_if.h"
#include "hw/hwreg.h"
//For mem mapping
void map_area7_init();
+16
View File
@@ -491,12 +491,28 @@ std::string disassemble_op(const char* tx1, u32 pc, u16 opcode)
}
else if (strcmp2(tx1,"FREG_N>"))
{
sprintf(buf,"FR%d=%f ", GetN(opcode), p_sh4rcb->cntx.xffr[16 + GetN(opcode)]);
regs += buf;
sprintf(buf,"FR%d",GetN(opcode));
}
else if (strcmp2(tx1,"FREG_M>"))
{
sprintf(buf,"FR%d=%f ", GetM(opcode), p_sh4rcb->cntx.xffr[16 + GetM(opcode)]);
regs += buf;
sprintf(buf,"FR%d",GetM(opcode));
}
else if (strcmp2(tx1, "FREG_M_SD_F>"))
{
sprintf(buf,"FR%d=%f ", GetM(opcode), p_sh4rcb->cntx.xffr[16 + GetM(opcode)]);
regs += buf;
sprintf(buf,"FR%d", GetM(opcode));
}
else if (strcmp2(tx1,"FREG_0>"))
{
sprintf(buf,"FR0=%f ", p_sh4rcb->cntx.xffr[16]);
regs += buf;
sprintf(buf,"FR0");
}
else if (strcmp2(tx1,"RM_BANK>"))
{
sprintf(buf,"R%d_BANK",GetM(opcode)&0x7);
+1
View File
@@ -46,6 +46,7 @@ enum DreamcastKey
EMU_BTN_MENU,
EMU_BTN_FFORWARD,
EMU_BTN_ESCAPE,
EMU_BTN_INSERT_CARD,
// Real axes
DC_AXIS_TRIGGERS = 0x1000000,
+7 -1
View File
@@ -23,6 +23,7 @@
#include "rend/gui.h"
#include "emulator.h"
#include "hw/maple/maple_devs.h"
#include "hw/naomi/card_reader.h"
#include "stdclass.h"
#include <algorithm>
@@ -86,6 +87,10 @@ bool GamepadDevice::handleButtonInput(int port, DreamcastKey key, bool pressed)
if (pressed && !gui_is_open())
settings.input.fastForwardMode = !settings.input.fastForwardMode && !settings.network.online;
break;
case EMU_BTN_INSERT_CARD:
if (pressed && settings.platform.isNaomi())
card_reader::insertCard();
break;
case DC_AXIS_LT:
if (port >= 0)
lt[port] = pressed ? 255 : 0;
@@ -286,7 +291,7 @@ void GamepadDevice::load_system_mappings()
{
std::shared_ptr<GamepadDevice> gamepad = GetGamepad(i);
if (!gamepad->find_mapping())
gamepad->resetMappingToDefault(settings.platform.system != DC_PLATFORM_DREAMCAST, true);
gamepad->resetMappingToDefault(settings.platform.isArcade(), true);
}
}
@@ -340,6 +345,7 @@ bool GamepadDevice::find_mapping(int system /* = settings.platform.system */)
if (cloneMapping)
input_mapper = std::make_shared<InputMapping>(*input_mapper);
perGameMapping = perGame;
rumblePower = input_mapper->rumblePower;
return true;
}
if (!perGame)
+16 -2
View File
@@ -56,7 +56,20 @@ public:
virtual void rumble(float power, float inclination, u32 duration_ms) {}
virtual void update_rumble() {}
bool is_rumble_enabled() const { return _rumble_enabled; }
bool is_rumble_enabled() const { return rumbleEnabled; }
int get_rumble_power() const { return rumblePower; }
void set_rumble_power(int power) {
if (power != this->rumblePower)
{
this->rumblePower = power;
if (input_mapper != nullptr)
{
input_mapper->rumblePower = power;
input_mapper->set_dirty();
save_mapping();
}
}
}
static void Register(const std::shared_ptr<GamepadDevice>& gamepad);
@@ -95,7 +108,8 @@ protected:
std::string _name;
std::string _unique_id;
std::shared_ptr<InputMapping> input_mapper;
bool _rumble_enabled = true;
bool rumbleEnabled = false;
int rumblePower = 100;
private:
bool handleButtonInput(int port, DreamcastKey key, bool pressed);
+3 -3
View File
@@ -480,8 +480,8 @@ void KeyboardDeviceTemplate<Keycode>::keyboard_input(Keycode keycode, bool press
// or the corresponding maple device (if any) isn't a keyboard
else if (gui_is_open()
|| port == (int)ARRAY_SIZE(kb_key)
|| (settings.platform.system == DC_PLATFORM_DREAMCAST && config::MapleMainDevices[port] != MDT_Keyboard)
|| (settings.platform.system == DC_PLATFORM_NAOMI && settings.input.JammaSetup != JVS::Keyboard)
|| settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|| (settings.platform.isConsole() && config::MapleMainDevices[port] != MDT_Keyboard)
|| (settings.platform.isNaomi() && settings.input.JammaSetup != JVS::Keyboard)
|| settings.platform.isAtomiswave())
gamepad_btn_input(dc_keycode, pressed);
}
+3
View File
@@ -55,6 +55,7 @@ button_list[] =
{ DC_AXIS_LEFT, "compat", "btn_analog_left" },
{ DC_AXIS_RIGHT, "compat", "btn_analog_right" },
{ DC_BTN_RELOAD, "dreamcast", "reload" },
{ EMU_BTN_INSERT_CARD, "emulator", "insert_card" },
};
static struct
@@ -185,6 +186,7 @@ void InputMapping::load(FILE* fp)
dz = std::min(dz, 100);
dz = std::max(dz, 0);
this->dead_zone = (float)dz / 100.f;
this->rumblePower = mf.get_int("emulator", "rumble_power", this->rumblePower);
version = mf.get_int("emulator", "version", 1);
if (version < 3)
@@ -412,6 +414,7 @@ bool InputMapping::save(const std::string& name)
mf.set("emulator", "mapping_name", this->name);
mf.set_int("emulator", "dead_zone", (int)std::round(this->dead_zone * 100.f));
mf.set_int("emulator", "rumble_power", this->rumblePower);
mf.set_int("emulator", "version", 3);
int bindIndex = 0;
Loaded 100 of 252 files, more files were not shown because too many files have changed in this diff. Show more