Compare commits

...

1105 commits

Author SHA1 Message Date
Ray Sollium
e7dc2bb993
Improve README 2025-01-15 19:03:53 +00:00
Ray Sollium
078c369dcd
Update README
Fix a typo from months ago that i haven't noticed till now
2025-01-15 19:01:45 +00:00
Ray Sollium
dfbcc47495
Improve README (Again)
I somehow managed to paste the wrong thing TWICE and pushed it to prod without noticing.
2025-01-12 20:36:26 -03:00
RaySollium99
fe3e0cbc36 Add BunkenTech Fontmap
Was originally going to use ImagineFloat, but decided to go with BunkenTech. It's not the same as ImagineFloat, but it's very similar, but will be free on my part
2025-01-12 20:34:17 -03:00
Ray Sollium
fa6b3579e7
Improve README 2025-01-12 20:31:40 -03:00
RaySollium99
40f540cd5a Change README
i'm back after 2 months bitch
2024-10-30 06:26:11 -03:00
Ray The Fox
c013d656c8
Update GitModules 2024-08-09 01:45:38 +00:00
Ray The Fox
7b4c3531ef Add XMB BGM (Ripped from PS3) 2024-08-08 22:28:14 -03:00
Ray The Fox
145ec916b9 Update GitIgnore AGAIN 2024-08-08 20:23:29 -03:00
Ray The Fox
92edf635f3 Remove Unused Version String 2024-08-08 20:23:09 -03:00
Ray The Fox
bf830343a6 Add XMB Background (PIC1), add Retro Dreams BGM (not implemented yet) 2024-08-08 20:23:00 -03:00
Ray The Fox
3c5ebb2ecc Accidentally removed the non-download link 2024-08-07 21:41:42 -03:00
Ray The Fox
27e4912ff6 Add To-do List to README 2024-08-07 21:41:03 -03:00
Ray The Fox
a31292d23b Update Gitignore to remove my terrible VSCode settings 2024-08-06 14:59:01 -03:00
Ray The Fox
fc6b8fca51 (T12) Separate Title Screen and Main Menu Backgrounds 2024-08-06 14:58:29 -03:00
Ray The Fox
163d9f8a1b Update .gitignore 2024-08-06 13:44:39 -03:00
Ray The Fox
8a142b8983 Add new backgrounds (Not implemented yet) 2024-08-06 13:44:24 -03:00
Ray The Fox
519c078685 Write a README file 2024-08-05 20:03:38 -03:00
Ray The Fox
8276aa84ac Remove Unused Red Select Color 2024-08-05 14:57:31 -03:00
Ray The Fox
2b9b9f4439 Disgusting hack to lower the main menu text 2024-08-05 14:45:00 -03:00
Ray The Fox
7f50eb2c20 (T7) Finally fixed SRAM save 2024-08-04 22:57:59 -03:00
Ray The Fox
a5654d9c38 I GIVE UP 🔥🔥🔥🔥 2024-08-04 22:48:05 -03:00
Ray The Fox
6ebee76883 Still not working btw 2024-08-04 22:29:42 -03:00
Ray The Fox
291e4fe9c7 Can you tell i don't code C (still not working) 2024-08-04 22:24:22 -03:00
Ray The Fox
52a2159bc8 Typo x2 2024-08-04 22:01:23 -03:00
Ray The Fox
c3a62e8c64 Fix REALLY STUPID typo that stopped this shit from compiling 2024-08-04 22:00:05 -03:00
Ray The Fox
078c7ede44 (T6) Update Gitignore (again), Update Name and Fix Savedata
Btw there's no T5 on the commit changes because i forgot to change from M1 for an entire version
2024-08-04 21:58:25 -03:00
Ray The Fox
d80333917d Change Icon 2024-08-04 19:33:02 -03:00
Ray The Fox
29e8f6406c MILESTONE 1 BABYYYYYY 2024-08-04 19:23:57 -03:00
Ray The Fox
79b5e8a900 (T4) Change main menu string, fix background and rom selector 2024-08-04 19:23:36 -03:00
Ray The Fox
477fd56aff Sorta changed the background (Need to resize), and failed to ignore the file extension 2024-08-04 17:51:25 -03:00
Ray The Fox
f770589dd0 Change Gitignore, Main Menu & ROM Directory
Long ass title cuz i am a loser ^^
2024-08-04 17:22:39 -03:00
Ray The Fox
f50b7edf80 Create PSP Readme
First compiled file gave me this so ¯\_(ツ)_/¯
2024-08-04 16:55:47 -03:00
kub
75db61b756 platform ps2, handle audio similar to psp 2024-07-22 08:31:21 +02:00
kub
ecc3f2ecc0 release 2.00 2024-07-19 19:21:26 +02:00
kub
11a1966bf3 core vdp, arm rendering speed optimisation 2024-07-18 21:36:43 +02:00
kub
1fad746a1f core vdp, fix layer/window borders for vertical window 2024-07-17 22:47:02 +02:00
Apaczer
4a347fbe94 platform/miyoo: scripted versioning
update pkg.cfg
2024-07-16 22:58:11 +02:00
kub
b4244cbb6d update README 2024-07-15 22:51:50 +02:00
kub
c12b126f06 platform miyoo, switch menu key to RESET 2024-07-13 21:41:51 +00:00
kub
a9d1e99533 core, adjustment for background color DMA 2024-07-12 23:11:37 +02:00
Apaczer
e3fa3ee270 platform-miyoo: change to IPK release output
create `platform/miyoo/pkg.cfg`
2024-07-12 23:11:37 +02:00
irixxxx
29dcbc52b2 add links to images 2024-07-11 23:08:55 +02:00
irixxxx
34070ccc34 add some images to readme 2024-07-10 21:43:29 +02:00
notaz
538982b062 mcd: unbreak cue search 2024-07-09 21:30:19 +02:00
kub
977e5db898 core, fix typo 2024-07-08 22:46:06 +02:00
kub
73411ac447 sound, add panning for ym2612 dac 2024-07-08 22:41:01 +02:00
kub
4af69a1df0 sms, improve pad handling (TR as output) 2024-07-05 21:48:38 +02:00
kub
13c9a48c26 ui, minor menu fix 2024-07-05 21:49:08 +02:00
kub
7bf552b5fa add/update copyright notices for substantially changed files 2024-07-02 22:55:50 +02:00
kub
2f0c5639c1 core z80, fix cycle counting if z80 in hold on frame change 2024-07-02 22:43:26 +02:00
kub
25559e5417 sms, add sram in codemasters mapper 2024-06-30 17:55:37 +02:00
kub
40172b9319 sms, improve system detection by extension 2024-06-30 17:19:34 +02:00
kub
543e97f6f0 sh2 drc, fix TAS instruction, some cleanup 2024-06-28 00:23:38 +02:00
kub
7401f7005f build, fix arch detection in configure 2024-06-28 00:23:38 +02:00
kub
cb4379b3bf sh2 drc, minor optimization for x86 backend 2024-06-28 00:23:38 +02:00
kub
c1812e1a85 core vdp, some cleanup 2024-06-28 00:23:38 +02:00
kub
6fd16ed6f5 core vdp, fix display enable in hblank 2024-06-27 23:39:45 +02:00
kub
711628f3a3 core z80, revert non-working ebde43d (bus blocking DMA) 2024-06-27 23:39:45 +02:00
kub
444c592a1d core vdp, fix status for very short DMA transfers 2024-06-27 23:39:45 +02:00
kub
da10229772 core vdp, change cram write sync 2024-06-27 23:39:45 +02:00
kub
c5ecd7a0bb core, some save state fixes 2024-06-27 23:39:45 +02:00
kub
f5c022a8e4 core, revisit ym2612 busy flag implementation 2024-06-27 23:39:44 +02:00
kub
e948a120ed sh2 drc, minor fix for x86 backend 2024-06-20 20:14:15 +02:00
kub
60ef69d631 libretro, gcc14 fixes 2024-06-20 20:13:29 +02:00
kub
cbb9a09837 core vdp, arm rendering fix (1st window col prio) 2024-06-18 22:45:02 +02:00
kub
e8ca10820c build, fix zstd asm file usage (used only for x86) 2024-06-15 16:21:10 +00:00
kub
7aca6897ad build, fix zstd asm file usage (used only for x86) 2024-06-15 16:26:12 +02:00
kub
7cbd42bc54 md, minor cleanup for region code handling 2024-06-15 10:15:19 +00:00
kub
6a996613a9 68k, minor debug fix for fame 2024-06-15 10:15:19 +00:00
kub
89319e4997 build, more lowercase on linux, plus minor changes 2024-06-15 10:15:19 +00:00
kub
7647f87b29 md vdp, fix v_counter reading, some cleanup 2024-06-15 00:12:11 +02:00
kub
31efd4546e sh2 drc, several bug fixes 2024-06-15 00:12:11 +02:00
kub
a43c77c0e5 build, fix libchd zstd support for libretro static linking 2024-06-15 00:12:01 +02:00
kub
4af2edc365 32x, fixes for comparing cycles 2024-06-02 08:03:12 +00:00
kub
38fd3bd866 sh2 drc, fix mul/add saturation 2024-06-02 08:03:09 +00:00
kub
68e50296e6 sh2 drc, small fixes (cycle counting, invalidation) 2024-06-02 07:55:40 +00:00
Tomáš Kelemen (vudiq)
8d04801518 remove fflush() call before exit()
the buffer is flushed anyways at exit() and fixes compile error with
gcc14:

    pico/carthw/svp/compiler.c: In function 'ssp_translate_block':
    pico/carthw/svp/compiler.c:1800:24: error: passing argument 1 of 'rfflush' from incompatible pointer type [-Wincompatible-pointer-types]
     1800 |                 fflush(stdout);
          |                        ^~~~~~
          |                        |
          |                        FILE *
    In file included from ./pico/pico_port.h:12,
                     from ./pico/pico_int.h:15,
                     from pico/carthw/svp/compiler.c:9:
    platform/libretro/libretro-common/include/streams/file_stream_transforms.h:89:25: note: expected 'RFILE *' but argument is of type 'FILE *'
       89 | int64_t rfflush(RFILE * stream);
          |                 ~~~~~~~~^~~~~~

this error presents itself when building the libretro core, so this
could be also solved by wrapping the call to fflush():

    #ifndef __LIBRETRO__
    		fflush(stdout);
    #else
                fflush((RFILE *)stdout);
    #endif
2024-05-25 10:26:16 +02:00
notaz
cc1174c988 update libchdr for zstd support 2024-05-24 16:25:20 +00:00
kub
3b480be4c0 core z80, partially revert ebde43d (bus blocking DMA)
it causes audio lag in OD2
2024-05-24 00:07:37 +02:00
kub
b72095041e sms, fixes to bios initialisation and mapper autodetection 2024-05-24 00:05:35 +02:00
kub
1eb630c232 md, no floating bus in cart address space 2024-05-23 19:17:28 +02:00
kub
75a6b6a954 md, add some unlicensed carts 2024-05-23 19:16:56 +02:00
kub
257baf1520 platform ps2, fixes for gcc14 2024-05-20 13:29:05 +02:00
kub
c055f15cd5 build, add ps2 to release script 2024-05-20 13:29:05 +02:00
kub
65b37c5a3b sh2 drc, fix conditional immediate for armv7 2024-05-19 20:45:44 +00:00
notaz
735a987b27 pandora: some fixes for 2.0 2024-05-18 23:21:41 +02:00
kub
faf754baf8 update copyright 2024-05-18 22:29:56 +02:00
kub
96e5982134 core vdp, reset fix 2024-05-18 22:29:56 +02:00
kub
2531b6fd16 sms, minor optimization 2024-05-18 22:29:56 +02:00
kub
4167049666 core, fix floating bus read for 68k (regression) 2024-05-18 22:29:49 +02:00
kub
864ac1d6a6 sound, don't reinitialize after menu if not needed 2024-05-18 21:21:54 +02:00
kub
67c9ba38cb core, improve system and mapper detection 2024-05-17 19:12:15 +00:00
kub
dab0c36316 build, change executable name to lowercase 2024-05-16 20:39:35 +00:00
kub
8341673054 32x, fix reset interrupt handling 2024-05-14 00:19:48 +02:00
kub
fb79e7baa8 platform opendingux, add some keys (gkd mini, rs97) 2024-05-12 10:07:51 +02:00
notaz
695e6de85e 32x, internal BIOS hack for jumping to 0x140 2024-05-08 01:20:01 +02:00
kub
52cb58c50d core z80, improve save/load (cycles) 2024-05-08 00:09:18 +02:00
kub
ebde43de9d core z80, bus blocking for VDP DMA 2024-05-08 00:09:18 +02:00
kub
274dd51a60 core z80, cycle counting fixes (reset, bus request) 2024-05-08 00:09:18 +02:00
notaz
c9f9453414 32x: adjust handlers according to hw tests
"Pico32x.regs[6] |= P32XS_RV;" had wrong offset, but tests show this
doesn't happen at all so remove.
2024-05-08 00:07:53 +02:00
kub
eec6905e0b 32x, some reset related fixes 2024-05-05 22:54:03 +02:00
kub
0290987ccb core vdp, fix regression (irq not cleared on disable) 2024-05-05 22:54:02 +02:00
kub
c5d8fe3c03 prerelease 2.00-beta3 2024-04-28 21:18:36 +02:00
kub
b8a38093ed core vdp, fix regression (irq not cleared on disable) 2024-04-27 10:12:30 +02:00
kub
4985bad0fb mcd, add poll detection for gfx busy 2024-04-27 10:12:30 +02:00
kub
e61dbac103 mcd, fix irq2 handling (not cleared on disable) 2024-04-27 10:12:25 +02:00
kub
ce5c904a39 mcd, improve pre/post reading 2024-04-27 10:11:38 +02:00
kub
c7b771de6c 32x, make sh2 sram poll detection less agressive 2024-04-24 21:51:01 +02:00
kub
d9bb2921ee mcd, implement pre/post reading in play/read state 2024-04-21 16:20:28 +02:00
kub
691abdfa0f mcd, some improvements (dma timing, interrupt handling) 2024-04-20 00:41:57 +02:00
kub
4447902711 mcd, revisit track handling in cdd 2024-04-20 00:41:57 +02:00
kub
db2b6d9966 core z80, fix cycle counting in reset state 2024-04-12 20:29:50 +02:00
kub
c7661b80ef md, fix vdp reset handling 2024-04-12 20:08:33 +02:00
kub
51d6248b95 md, fix vdp reset handling 2024-03-28 21:39:12 +01:00
kub
3e491c7880 prerelease 2.00-beta2 2024-03-26 22:52:50 +01:00
kub
62e763ecdd platform, small fixes for Pico, updated readme 2024-03-26 22:52:50 +01:00
kub
0b12a5a00a core 68k, fix compiler warning in fame 2024-03-26 22:52:50 +01:00
kub
5f9901e098 libretro, add Pico pad overlay and storyware pages handling 2024-03-26 00:30:53 +01:00
kub
15cc45c0da platforms, display pad overlay and storyware pages for Pico 2024-03-25 23:08:23 +01:00
kub
da4148881e sms, fix save/load bugs (irq, mapper) 2024-03-24 17:45:10 +01:00
kub
64360d13b0 core, big endian fix (save/load) 2024-03-21 19:10:44 +01:00
saulfabreg Wii VC Project
a33c391027 Libretro: silence a warning regarding to memmap 2024-03-20 23:55:14 +01:00
kub
0ef1674dd1 drc: only use 64kb aligned tcache_default if on arm linux 2024-03-18 19:40:01 +01:00
kub
c87e36d750 core+platforms, revise pico pen handling
the MSB in the tablet position register denotes pen on surface.
add logic and a hotkey for handling pen not on surface. This allows
for repositioning of the pen without the storyware reacting to it.
2024-03-18 18:24:54 +01:00
kub
9f29605f55 core, floating bus read for 68k in some more places 2024-03-16 15:58:47 +01:00
kub
71f9c68f5b core z80, improve timing for bus request/grant timing from 68k 2024-03-14 23:18:26 +01:00
kub
8b0e2b4f9a core 68k, make musashi timing more similar to fame 2024-03-14 23:18:09 +01:00
kub
1ab87d2b9a core 68k, minor improvement for division in fame 2024-03-14 23:17:37 +01:00
kub
5adcc16534 68k, some fixes for musashi 2024-03-10 01:26:06 +00:00
notaz
eac7a97e4f drc: align tcache_default to 64k on arm
Newer arm64 hw supports 64k pages, and recent Linux distros provide
kernel packages like linux-image-generic-64k (can be used on r-pi4
with Ubuntu for example). It affects 32bit mode also, so assume that
an arm32 binary compiled for vfp may be used on such kernel.

Without this mprotect() fails to set exec permission because of bad
alignment.
2024-03-09 22:02:10 +01:00
saulfabreg Wii VC Project
8cca318242 Libretro: Fix Wii compiling by adding required -ffat-lto-objects
Otherwise when compiling the final dol will result in compilation errors because of missing Libretro dependencies.
(dirty, quick-fix) workaround for stop the compiler messages of "plugin needed to handle lto object"
2024-03-09 19:06:59 +01:00
kub
3f5918225a core, fix 68k cycles in cyclone,fame (exceptions,bit ops,ADDI.L,TAS,CHK,MUL*,DIV*)
also syncs these changes between fame and cyclone

in accordance with the test_inst_speed, available here:
https://gendev.spritesmind.net/forum/viewtopic.php?t=3321
DIV* is only closely approximated, it can be slightly on the high side.
2024-03-07 21:19:10 +01:00
kub
02d578601b core, fix crash bug in DrZ80 (SP wrap) 2024-03-07 20:36:00 +01:00
kub
83025d7abe core, implement ym2612 busy flag 2024-03-04 21:59:52 +01:00
kub
c066c40ba9 core z80, more timing fixes 2024-03-04 21:59:52 +01:00
kub
1d78204a90 prerelease 2.00-beta1 2024-03-03 13:02:13 +01:00
kub
a17fb0210b core z80, some timing improvements 2024-03-03 13:01:51 +01:00
kub
56ec20d262 psp, small fixes 2024-03-03 09:45:01 +01:00
kub
e28fd20f08 psp, revisit audio handling
sound rates 44100, 22050, 11025 Hz, internally upsampled
conversion to stereo since mono isn't supported well on psp
2024-03-02 10:19:57 +01:00
kub
d12dd1b4ea psp, rendering fix, some build changes 2024-03-02 10:19:57 +01:00
kub
80f51a1d59 core, slightly increase accuracy of some hw timers 2024-03-02 10:36:49 +01:00
kub
506adbd5eb core, another fix for z80 reset 2024-03-02 10:34:50 +01:00
kub
2a87da47c0 ps2, fix some audio related bugs 2024-03-02 10:34:04 +01:00
kub
d128474f6f mcd, fix crash (plat_mmap not zeroing memory) 2024-02-26 23:10:35 +01:00
kub
2eeee072ea mcd, increase audio volume slightly 2024-02-23 19:23:41 +01:00
kub
4aaedc899e mcd, fix audio not playing when buffer RAM enabled 2024-02-23 19:23:37 +01:00
kub
ad43165afc core, fix z80 irq handling, reset defaults (cz80, drz80) 2024-02-22 21:01:37 +01:00
kub
bfe516c3a9 core, system detection by extension in zip files 2024-02-21 19:12:10 +01:00
kub
d89e9fb04a core, fix arm asm regression (bg color DMA crash) 2024-02-21 19:10:44 +01:00
kub
7f3b89a7f2 ci, use available processor cores 2024-02-21 00:29:17 +01:00
kub
d97d056c46 core md, assert z80 vint for complete scanline 2024-02-21 00:29:17 +01:00
kub
a0abaf2ada ps2, minor fixes 2024-02-21 00:29:17 +01:00
kub
f3ae9cb900 Merge branch 'irixxxx/ps2-merge' 2024-02-18 23:58:18 +01:00
kub
e2b9687b3f ps2, more audio fixes 2024-02-18 23:30:36 +01:00
kub
fd604aa720 ps2, kludge for handling audsrv shortcomings 2024-02-18 23:30:36 +01:00
kub
dedf7fa7d5 ps2, kludge for timer bugs in ps2sdk 2024-02-18 23:30:36 +01:00
kub
3eb1d64585 ps2, minor audio and gfx fixes 2024-02-18 23:30:36 +01:00
kub
4abc40d56b fixes for audio and video, add psp-like scaling 2024-02-18 23:30:36 +01:00
Francisco Javier Trujillo Mata
455cecf973 Sound almost working 2024-02-18 23:30:36 +01:00
Francisco Javier Trujillo Mata
b4a8b47113 Some progress about centering image 2024-02-18 23:30:36 +01:00
Francisco Javier Trujillo Mata
6724ae42f3 Some clean up around emu.c 2024-02-18 23:30:36 +01:00
Francisco Javier Trujillo Mata
30f7602e65 Disable alpha and improve vsync logic 2024-02-18 23:30:36 +01:00
Francisco Javier Trujillo Mata
1107e618f5 Starting to see the emulator on the screen 2024-02-18 23:30:36 +01:00
Francisco Javier Trujillo Mata
8633b583f0 Starting to see the menu in the screen 2024-02-18 23:30:36 +01:00
Francisco Javier Trujillo Mata
862e969bab Adding background objects 2024-02-18 23:30:36 +01:00
Francisco Javier Trujillo Mata
888ca0b83b Adding gskit dependency 2024-02-18 23:30:34 +01:00
Francisco Javier Trujillo Mata
ebf2b007d1 Starting to copy some logic for emu from PSP 2024-02-18 23:30:09 +01:00
Francisco Javier Trujillo Mata
e22b24b81a First dummy input implementation 2024-02-18 23:30:09 +01:00
Francisco Javier Trujillo Mata
8b65c92f1f Use MenuX2 in PS2 2024-02-18 23:30:09 +01:00
Francisco Javier Trujillo Mata
9b4c95a951 Fix folder creation 2024-02-18 23:30:09 +01:00
Francisco Javier Trujillo Mata
936f164b55 Starting to boot 2024-02-18 23:30:09 +01:00
Francisco Javier Trujillo Mata
cb77495873 First PS2 compilation 2024-02-18 23:30:04 +01:00
kub
089f516d6c make sound rates platform dependent 2024-02-17 21:54:33 +01:00
kub
33bde0c3c5 psp, fix for pspdev update 2024-02-15 00:07:36 +01:00
kub
af386f93c1 platform, fix BGR/RGB menu handling 2024-02-14 23:48:28 +01:00
kub
b4bc262418 platform, cleanup main emu loop 2024-02-14 23:48:06 +01:00
kub
b38c0ea6f9 core, fix some bugs reported by ASAN 2024-02-14 23:48:06 +01:00
kub
b5d8374c6a build, add -flto for all builds if available 2024-02-14 23:48:06 +01:00
kub
f1dbe7642f core, improve bg color DMA handling (and some vdp cleanup) 2024-01-28 22:34:17 +01:00
kub
db1ee7a2df core, handle background color DMA (arm asm) 2024-01-28 21:25:04 +01:00
kub
492c47c4b8 core, some updates for Pico adpcm 2024-01-24 21:14:42 +01:00
kub
a914c976f8 prerelease 2.00-alpha3 2024-01-23 22:56:31 +01:00
kub
cbe7853333 update libpicofe (redraw event handling) 2024-01-23 22:55:38 +01:00
kub
70efc52db8 core, implement GG stereo 2024-01-23 22:21:15 +01:00
kub
fa4e0531d4 core, improve pico save/load (ADPCM state, page, etc) 2024-01-23 22:21:15 +01:00
kub
f1b425e380 core, complete rewrite of Pico adpcm driver 2024-01-22 19:44:09 +01:00
kub
831bffdd31 core, fix Pico hardware region code 2024-01-20 17:29:22 +01:00
kub
e348af76ec core, revisit Pico sound handling 2024-01-20 17:23:44 +01:00
kub
ba2b97dc24 core, fix Pico horizontal irq (on irq level 5) 2024-01-20 17:15:51 +01:00
kub
214a6c624c core+platforms, add SMS option to select TMS palette for gfx modes 0-3 2024-01-13 16:31:43 +01:00
kub
dca20effa2 platforms, revisit Pico ptr handling 2024-01-13 12:09:16 +01:00
kub
724db457da core, handle background color DMA (aka fantom bitmap) 2024-01-13 12:09:16 +01:00
notaz
68e06234e3 sound: fix ym2612 freq latch
there is only a single register, as described in:
http://www.mjsstuf.x10host.com/pages/vgmPlay/vgmPlay.htm
2024-01-12 21:34:19 +01:00
notaz
ca980e1b0a pandora: allow to move the overlay partially offscreen
to allow to cut off black bars, if the user chooses to do so
2024-01-07 11:32:53 +01:00
notaz
70db485b44 config: save disabled options also
Pandora uses disabled menu options to store the layer position
(mee_range_hide() menu entries) and actually modifies them using
a special menu handler.
2024-01-07 11:32:53 +01:00
kub
82f97f10a1 prerelease 2.00-alpha2 2023-12-14 22:31:28 +01:00
kub
58fc34b1d6 build, odbeta and opendingux cleanup 2023-12-12 23:35:02 +01:00
kub
85174a6d8d build, cleanup
- remove/rename some platforms from configure
- new rg99 odbeta build, courtesy of sydarn
- pandora support, courtesy of notaz
2023-12-12 23:35:02 +01:00
kub
2a5ca3d5f0 update libpicofe (parallel menu keys) 2023-12-03 21:57:44 +01:00
notaz
92efe29e6a pandora: move PicoDrawSetOutFormat 2023-12-03 21:52:28 +01:00
notaz
8a40739892 cosmetic fixes for pandora port 2023-12-03 21:52:28 +01:00
sydarn
830935963d cleanup rg99 specifics and remove odbetaflag 2023-12-03 21:35:51 +01:00
sydarn
0e7c531169 ODBETA: use 320x240 sdl surface when not hw scaling on 320x480 LCDs 2023-12-03 21:35:51 +01:00
kub
c180662e07 sms, improve changing of video mode 2023-12-03 17:46:59 +01:00
kub
6396f46107 sound, fix ffw crash in PSG 2023-12-03 14:56:24 +01:00
kub
0f1b9bccc0 sdl, improve redraw in file selector 2023-12-03 14:50:51 +01:00
kub
a0ecb29979 core, fix no ym2612 timers if z80 in reset 2023-12-01 01:09:25 +01:00
kub
fc07fe2b4e psp, revisit scaling 2023-11-30 20:35:49 +01:00
kub
4b24b6b74c build, fix cross compiling under osx 2023-11-24 18:51:32 +01:00
kub
575d224780 psp, fix enable sound option 2023-11-24 18:51:32 +01:00
kub
8a553c6b3d update libpicofe (file selector) 2023-11-24 18:51:31 +01:00
kub
48fc9762de psp, fix GU hardware rendering 2023-11-24 18:51:31 +01:00
kub
96a972dcec core, fix H32 mode in fast renderer 2023-11-23 21:11:36 +01:00
kub
9215679134 build, update psp toolchain container 2023-11-23 21:11:34 +01:00
kub
43ef4071da sound, faster resampler for SMS FM 2023-11-23 21:08:13 +01:00
kub
250c8ffbc0 build, revisions and fixes for opendingux based platforms 2023-11-23 21:07:56 +01:00
Francisco Javier Trujillo Mata
a20af2f935 Clean-up makefile 2023-11-16 00:04:48 +01:00
Francisco Javier Trujillo Mata
4b2223986c Use posix functions for PSP 2023-11-16 00:04:48 +01:00
kub
f2554438f8 build, revisions and fixes for opendingux based platforms 2023-11-15 22:58:02 +00:00
kub
7f09f5c477 build, switch to static miyoo toolchain 2023-11-14 23:11:59 +00:00
kub
6e8a71eda0 prerelease 2.00-alpha1 2023-11-09 22:56:00 +00:00
kub
02ed0c7f60 build, add odbeta 2023-11-09 23:44:01 +01:00
zoltanvb
6bd90c9666 Propagate GIT_REVISION to REVISION 2023-11-07 23:45:15 +01:00
kub
801daef9aa build, remove non-working release actions 2023-11-01 23:56:37 +02:00
kub
5038e421e9 Merge pull request #96 from 'techmetx11/master'
* techmetx11/master:
  Add hack for unlicensed games that don't handle the Z80 bus properly
2023-11-01 22:39:44 +01:00
kub
df765ed91b core, fix bug in m68k state saving
thanks to bnister for pointing this out
2023-10-26 23:52:07 +02:00
kub
ec0357587e build, cleanup after toolchain container changes 2023-10-26 23:10:17 +02:00
kub
3a6b0cc004 revisit release script 2023-10-26 19:03:50 +00:00
kub
3167aa9a94 compile fixes for CI 2023-10-26 19:03:50 +00:00
kub
725e007ae5 revisit CI
using a set of toolchain containers from my toolchains repo
support more platforms, artifact uploading, some release preparation
2023-10-26 18:42:26 +00:00
kub
d818246c51 handle "Mega Drive" naming consistently 2023-10-26 18:42:25 +00:00
kub
694427bea4 more changes to readme's 2023-10-26 18:42:25 +00:00
kub
324dbe0473 readme, some cleanup 2023-10-23 22:02:03 +02:00
kub
31a082519a Merge pull request #88 from 'upstream/irixxxx'
* upstream/irixxxx:
  readme: make it more neutral
2023-09-03 22:05:02 +02:00
kub
1a9da199e8 platform, revisit menu, add option profiles 2023-09-01 23:02:43 +00:00
techmetx11
a67db32a4a
Add hack for unlicensed games that don't handle the Z80 bus properly 2023-08-21 16:21:25 +01:00
kub
bccd8832dd libretro, fix crash when exiting 32x 2023-08-11 12:34:31 +00:00
kub
c9076db928 sms, handle some more special cases 2023-07-20 21:09:34 +00:00
kub
f3c2f81e89 platform, menu revision 2023-07-20 20:25:59 +00:00
kub
ca206ba1aa sms, some handling for gg carts running in sms mode 2023-07-17 22:02:20 +02:00
kub
46b4c1d322 core, optimize vcounter handling 2023-07-17 21:16:38 +02:00
kub
7021622153 core, fix z80 vcounter value 2023-07-12 22:35:33 +02:00
kub
adffea8dae 32x, improve pwm volume accuracy 2023-07-11 21:43:00 +00:00
kub
7263343dc7 core, improve 68k timing accuracy 2023-07-11 21:18:05 +00:00
kub
a5aae2c39f sms, fix menu background scaling and position 2023-07-06 17:25:47 +00:00
kub
05d2acaeb2 mcd, fix audio crash after end of last track 2023-07-05 19:54:40 +00:00
kub
ae4d881a2f sound, some ym2612 arm cleanup 2023-07-03 23:45:46 +02:00
kub
f061b89d25 z80, minor fixes to drz80 + cz80 to bring them in sync 2023-07-03 23:37:22 +02:00
kub
9961d9fdb8 32x, fix disabling via ADEN (memory leak, mcd) 2023-07-03 23:29:51 +02:00
kub
9f7abd68df 32x, add disabling via ADEN (for testpico) 2023-06-30 21:44:26 +00:00
kub
0e2e188e1e sound, improve ym2612 timers implementation 2023-06-30 19:12:53 +00:00
kub
914525c3d5 mcd, fix no chd music in some cases 2023-06-29 19:54:07 +00:00
kub
c3d70d1305 sound, improve ym2612 timers implementation 2023-06-23 19:25:52 +00:02
kub
e0c4dac19c md, improve z80/68k synchronization 2023-06-23 19:21:10 +00:02
kub
f3876af7f9 sound, fixes for ym2612 (ARM and C) 2023-06-21 18:15:33 +00:00
kub
70ef073f66 add CI for psp 2023-06-16 23:43:56 +00:00
notaz
ccc39358b0 sound: fix ym2612 forgetting lfo state when dac is on
for less bad audio in OD2
2023-06-16 11:39:17 +02:00
notaz
8013663ec2 add CI for GP2X also
no helix as it has (had?) weird license IIRC
2023-06-15 08:46:27 +02:00
notaz
842f4e44d4 attempt some CI building using github actions 2023-06-15 08:46:27 +02:00
notaz
f20ad52307 platform: revive pandora build 2023-06-15 08:46:27 +02:00
notaz
225260ba40 sound: fix ym2612 address handling
I already fixed this back in 2017 with
151df6adf9, but forgot about
ym2612_write_local(). Fixes missing sounds in Overdrive2.
2023-06-13 11:05:19 +02:00
kub
5864c4214a core, regression fix for h32 scaling 2023-06-11 21:17:50 +00:00
kub
17c1401b44 32x, fix softscale enabled by 32x
also some streamlining cleanup in the drawing code
2023-06-11 19:11:18 +00:00
kub
f81718cbb8 32x, fix regression in poll detection 2023-06-09 19:27:21 +00:00
kub
f61d0a4534 core, testpico fixes 2023-06-09 19:22:51 +00:00
kub
3d7abd6905 32x, fix startup crash 2023-06-07 21:21:58 +00:00
kub
a18d5e22b3 md, fix carthw.cfg parsing 2023-06-05 22:21:16 +00:00
kub
3615ff7283 Merge pull request #89 from upstream/irixxxx_xin1
* upstream/irixxxx_xin1:
  carthw: more x-in-1 carts
  carthw: more accurate x-in-1 pirate handling
2023-06-05 22:14:52 +00:00
notaz
0a9bec0289 carthw: more x-in-1 carts
Also regenerate pico/carthw_cfg.c
2023-06-06 00:31:40 +03:00
kub
28165a19e4 core, always allocate a power of 2 for cartridges 2023-06-05 18:06:28 +00:00
kub
12d506baa8 libretro, more build fixes 2023-06-05 18:05:27 +00:00
kub
ab43a4b2fd libretro, fix build conflict 2023-06-05 18:05:27 +00:00
notaz
04cb5a192d carthw: more accurate x-in-1 pirate handling
There is no A0 so it should be masked out. Even though the cart could
use use LWR as A0, it's not actually connected as seen here:
http://gendev.spritesmind.net/forum/viewtopic.php?f=2&p=37995
2023-06-05 00:41:32 +03:00
notaz
3314e88244 readme: make it more neutral
I'd like the readme to not look weird in notaz/picodrive when I merge
all the changes, where it will be unclear who the 1st person pronoun
refers to. Several people have put quite some effort into it, so I think
it's best not to highlight anyone.

Also remove the old readme which has become outdated.
2023-06-05 00:31:51 +03:00
kub
69d69a4f63 mcd, fix prototype 2023-06-04 10:13:53 +00:00
kub
78562415ff core, fix crash if image couldn't be loaded 2023-06-03 07:50:23 +00:00
kub
d8a897a6db 32x, improve poll detection 2023-06-03 07:49:17 +00:00
kub
805fbe6faa 32x, fixes for msu 2023-05-30 22:10:12 +00:00
kub
411b2c1949 mcd, fixes for msu 2023-05-30 22:07:56 +00:00
kub
02f3222feb platform, basic msu-md support
loading a .cue file will look for a cartridge image with the same basename
and an extension of "gen", "smd", "md", "32x".
2023-05-28 13:56:55 +00:00
kub
f27a1749fe mcd, preparations for msu support (arm version) 2023-05-26 20:45:13 +00:00
kub
02ff025479 mcd, preparations for msu support 2023-05-26 19:36:50 +00:00
kub
178a9b683c mcd, fixes and improvements by mcd-verificator 2023-05-19 14:12:35 +00:00
crashGG
44a6c67823 fix .bin extension support for archives
fix the issue which can not load roms with the extension ".bin" in a zip package.
2023-05-15 09:27:24 +02:00
kub
c36dbc1dcd mcd, fix Word-RAM in 2M mode 2023-05-11 22:39:28 +00:00
kub
4a55f64a5d mcd, regression fix
yikes...
2023-05-11 22:20:02 +00:00
kub
f16f0d647f mcd 68k, fix autoload for cyclone 2023-05-11 22:06:23 +00:00
kub
26d58060f4 32x, tiny optimization 2023-05-10 22:23:32 +00:00
kub
8eeb342641 mcd, some cleanup, fix Word-RAM in 2M mode 2023-05-10 22:20:06 +00:00
kub
02db230830 mcd, improve cpu scheduling 2023-05-09 19:21:47 +00:00
kub
3a77090514 build, add ASAN, some CFLAGS changes, add revision 2023-05-02 20:19:18 +00:00
kub
83a9e30508 sh2 drc, cleanup and minor fixes (risc-v, division, typos) 2023-05-01 09:08:23 +00:00
kub
110a49ed2a platform gp2x, fix compilation with original toolchain (gcc 4.1) 2023-05-01 08:59:49 +00:00
kub
97232a47c9 core vdp, implement partial line blanking 2023-04-27 22:24:21 +02:00
kub
f9ed944604 core vdp, avoid rendering if no changes to RAMs/registers
mainly benefits 32X in faster/fastest rendering mode, 0-5% saved
2023-04-27 22:18:55 +02:00
kub
0c9c8e4796 core vdp, some cleanup 2023-04-27 21:19:56 +02:00
kub
133006a9d4 core, improve 68K/Z80 timing 2023-04-24 23:50:06 +02:00
kub
ae9a76c90d core vdp, improve sprite rendering
implements kabuto's phase 2, fixes rotating 3D blocks in Overdrive 2
2023-04-12 18:11:29 +00:00
kub
a80b0b42e1 svp drc, fix crash in jump patch 2023-04-11 19:08:36 +00:00
kub
134092feb7 md, implement z80 cycle stealing when accessing 68k bus
this fixes sound issues in Overdrive 2
2023-04-05 20:02:47 +02:00
kub
d515a352b3 core vdp, fix sprite rendering issues with Overdrive 1/2 2023-04-05 20:00:37 +02:00
kub
c7e1c39b28 core, make system detection by extension case insensitive 2023-03-26 10:35:39 +00:00
kub
ac89144969 md vdp, fix sprite parsing (done on previous line) 2023-03-26 10:33:29 +00:00
kub
e5a1d4c5f1 sms, cleanup, add missing tms palette to gp2x 2023-03-07 21:57:33 +00:00
kub
39194ef19e platform sdl, add missing prototype 2023-03-07 21:56:11 +00:00
kub
e278f08bed sh2 drc, fix 64 bit multiplication in ppc and riscv backends 2023-03-07 21:54:36 +00:00
kub
a26e663957 core, fix arm rendering regression after 8 bit changes 2023-02-23 22:12:57 +00:00
kub
0aa63fce12 core, revisit Sega 8 bit hardware handling 2023-02-22 23:22:45 +00:00
kub
cab84f29e5 core, preparations for sc-3000 support 2023-02-18 20:57:16 +00:00
kub
ecf8764253 sms vdp, fix TMS modes, tile count off by one 2023-02-18 20:45:51 +00:00
kub
c989b8fec1 platform sdl, fix minor bug in window size handling 2023-02-18 20:45:50 +00:00
kub
5aa5700685 platform sdl, fix minor bug in window size handling 2023-02-12 22:51:44 +00:00
kub
e64742875a platform, move keyboard menu keys for L,R to BS,TAB
they should not be on printable chars for correct handling in directory
listings, and BS+TAB should be the same on all(?) international keyboards.
2023-02-07 23:19:23 +00:00
kub
572cf80e38 core vdp, fix regression (switching V30->V28 in lines 225-239) 2023-02-07 23:10:22 +00:00
sndream
9ec3b5ac0e rg99 support 2023-01-16 21:50:11 +01:00
kub
95788d2ff2 sh2 drc, minor improvement for PS3 ABI handling 2023-01-12 23:02:25 +00:00
OsirizX
1ef527e93b Apply some cleanups to the abicall macros 2023-01-12 21:01:14 +01:00
OsirizX
08be5f1dab Add dynarec support for PS3 2023-01-12 21:01:14 +01:00
kub
0512a22869 sh2 drc, wrap generated function ptrs if called from host 2023-01-09 20:45:10 +00:00
kub
e1b916547d update submodules, use lzma-19.00 with newer libchdr
lzma-22.01 doesn't compile cleanly with some libretro platforms
2022-12-21 12:10:24 +00:00
kub
d5288c2a41 update submodules, fix for newer libchdr 2022-12-21 08:03:05 +00:00
kub
14b19ad7c8 update submodules 2022-12-20 21:58:06 +00:00
kub
19469da385 32x, fix soc code (sh2 sr register handling) 2022-12-20 21:37:21 +00:00
kub
7b02a2c3e3 32x, improve sh2 scheduling 2022-12-20 21:34:13 +00:00
kub
fe8f2d963e 32x, hacks for roms with caching related problems 2022-12-20 21:32:24 +00:00
kub
ebd9c86a6c platform, clear status remnants after renderer switching by hotkey 2022-12-19 22:03:43 +00:00
kub
35821b373c Revert 4ec1247 as it cause more troubles than it solves 2022-11-25 19:26:37 +00:00
kub
aa9c5aa559 sh2 drc, minor fix for arg passing in calls from generated to C code 2022-11-21 21:19:34 +00:00
kub
4ec1247d23 32x, tentative kludge for blackthorne 2022-11-21 21:15:51 +00:00
kub
eb990fd62a 32x, reset handling and synchronization changes 2022-10-28 19:55:40 +00:00
kub
7e0c38c9c7 psp, fix vsync synchronisation 2022-10-16 20:17:42 +00:00
kub
2c4675a993 core, fix cpu sync regression 2022-10-16 20:17:42 +00:00
kub
043ccbf45f fix some gcc warnings 2022-10-16 20:17:39 +00:00
kub
e44c606f39 pico, fix psg sound and fast forward 2022-10-14 18:47:20 +00:00
kub
c9d5f41b0a 32x, minor poll detection fix 2022-10-14 18:42:43 +00:00
kub
b074a2b5b6 mcd, minor optimization for poll detection 2022-10-13 19:25:25 +00:00
kub
fdaf9d10bd core, improve mcd+32x cpu synchronization 2022-10-12 21:44:32 +00:00
kub
db8af214be generic, fix debug menu rendering 2022-10-12 21:23:49 +00:00
kub
946c3b0ef5 32x, make 68k poll detection less agressive 2022-10-08 11:03:42 +00:00
kub
f338a562e9 sh2 drc, fix bug in jump patching for arm64 2022-10-06 19:46:03 +00:00
kub
e2a5b098e0 core, TH input latency only if output was low 2022-10-04 21:11:26 +00:00
kub
6c6d449ec5 core, add TH pad pin latency (load state regression) 2022-10-03 16:42:41 +00:00
kub
e05680a2b9 core, add TH pad pin latency (regression after 5 min) 2022-10-03 08:42:18 +00:00
kub
66e9abff6d core, add TH pad pin latency after switching to input 2022-10-03 07:55:25 +00:00
kub
54f74b8100 sdl, limited redraw event processing for sdl window and overlay modes
improves window resizing within the limits of libpicofe. Proper
windowing support would need a redesign.
2022-10-01 08:40:29 +00:00
kub
a2d1369cb5 psp, enable using new pspdev, fix some bugs 2022-09-29 23:24:43 +00:00
cmitu
0e67fb6011 configure: fix mcpu compiler parameter for RPI targets 2022-09-28 21:57:03 +02:00
kub
4182483ea2 sms, fix center tms text mode (mode 1) 2022-09-28 18:53:27 +00:00
kub
c05ec65ef1 gp2x, small optimization 2022-09-28 18:52:26 +00:00
kub
12ffc46933 platform, fix emu loop timing for vsync enabled 2022-09-28 18:51:19 +00:00
kub
a1ef15a783 platform sdl, fix screen clearing if line pitch isn't width 2022-09-28 18:46:32 +00:00
kub
6370b1d401 psp, more fps, improve sms/gg scaling 2022-09-28 18:43:33 +00:00
kub
96948bdfc8 sms, add fast renderer, remove 1st column (8 px) if blanked 2022-09-25 10:03:06 +00:00
kub
23e4719638 generic ui, add basic GLES support 2022-09-17 07:25:17 +00:00
kub
7c6f79147b sms, add xor 4x8k mapper 2022-09-14 19:33:02 +00:00
kub
f9b966dec6 mcd, fix gfx (32x32 stamp) 2022-09-14 19:30:32 +00:00
kub
6ce10a4308 core+platforms, harmonise supported extensions 2022-09-14 19:30:32 +00:00
kub
2ec448a8ce sound, fix ym2413 fm sound load/save 2022-05-11 00:18:47 +02:00
kub
732c328c41 z80, fix drz80 save (regression) 2022-05-09 23:14:40 +02:00
kub
56e0b86559 core vdp, fix out-of-bounds vram access for save/load 2022-05-09 21:59:52 +02:00
kub
7c16d1357b sms, fix mappers (save/load for sega, korea, 8kbram) 2022-05-09 21:59:52 +02:00
kub
46cbe781eb z80, improve cz80+drz80 compatibility 2022-05-04 20:27:44 +02:00
kub
5711398c4a z80: fix AF pop+push in DrZ80 (F bits 3+5 stack value unchanged) 2022-05-01 23:56:04 +02:00
kub
e1e8ca17be md, reworked cart protection handling, added some unlicensed 2022-04-30 14:07:58 +02:00
kub
27b26d0478 sound, minor FM filtering optimization 2022-04-30 14:04:28 +02:00
kub
72c2a04a9d core vdp, fix status reading synchronisation 2022-04-22 20:50:20 +02:00
kub
364be97d1b ui, fix skin for opendingux+linux 2022-04-20 19:26:16 +02:00
kub
36b2f2931f libretro, fix classic_arm builds, minor cleanup 2022-04-20 00:00:43 +02:00
kub
a5085db3ea Merge from libretro/master:7ff457f for repo synchronization 2022-04-19 23:58:59 +02:00
kub
45d0add214 ui, fix generic skin 2022-04-19 23:18:56 +02:00
kub
b4c25401da sh2 drc, improve cycle resolution for poll detection 2022-04-19 23:18:56 +02:00
kub
192ab01579 core, improve extension handling 2022-04-19 23:18:56 +02:00
kub
68a950875c sound, add FM filtering 2022-04-19 23:18:56 +02:00
kub
21e0cd52e6 ui, revisit menu 2022-04-19 23:18:56 +02:00
kub
5c7cd0590e libretro, fix native sound rate
thanks to jdgleaver for pointing this out
2022-04-10 07:45:03 +00:00
kub
a990d9c434 ui, revisit menu 2022-04-09 22:30:44 +02:00
Vladimir Serbinenko
f1e31ac6d4 Add missing pico init in case of successful autodetect 2022-04-09 22:10:43 +02:00
kub
47e73a93a4 libretro, fix compilation for unix armv7 2022-04-09 21:55:30 +02:00
jdgleaver
906cc85456 (libretro) Prevent illegal usage of RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO/RETRO_ENVIRONMENT_SET_GEOMETRY environment callbacks 2022-04-08 18:24:53 +02:00
kub
a987b67801 sound, fix config save/load for native quality mode 2022-03-31 22:11:05 +00:00
kub
e2e2b6ad1b sound, prepare FM filtering 2022-03-31 19:51:15 +02:00
kub
882f697ad4 sound, add native rate mode, change resampling 2022-03-31 19:51:03 +02:00
kub
d26d4c2965 build, add miyoo to release script 2022-03-11 21:15:35 +00:00
kub
f591b83785 core vdp, minor fifo write optimisation 2022-03-08 09:46:57 +00:00
jSTE0
f507a70379 platform: Add miyoo support
Add support for the miyoo platform, another SDL-based platform with a
small cache CPU and its own input mappings.
2022-03-06 23:06:23 +01:00
kub
f8aaa200cf platform sdl, preliminary window resizing fixes
picodrive doesn't handle resize events, so it's not really working :-/
it however uncovered some bugs and strange behaviour, though
2022-03-06 18:39:46 +00:00
kub
e48f3f2795 sms, some minor fixes and additions for sg-1000 2022-03-01 21:07:21 +00:00
kub
df6c895c5c sms, add sg-1000 support 2022-02-28 21:45:50 +00:00
kub
216c9f17fa sms, add sg-1000 on-cart RAM mapping 2022-02-27 11:12:15 +00:00
kub
3611781e65 sms, autodetection for sg-1000 ram extension 2022-02-27 09:57:50 +00:00
kub
171fb8cc14 sms, mapper for taiwanese sg-1000 ram extension 2022-02-26 21:52:43 +00:00
kub
aaef4b945e sms, add basic sg-1000 support 2022-02-26 10:19:07 +00:00
kub
22917adcff sms, add missing TMS VDP modes 2022-02-26 09:41:38 +00:00
kub
da64996b0d update libpicofe 2022-02-22 22:31:01 +00:00
kub
8df4ddba1e platform sdl, improved menu keymap for international keyboards 2022-02-22 22:26:40 +00:00
kub
74bd70403b platform sdl, add config file option for fullscreen 2022-02-22 20:40:34 +00:00
kub
bd9cbae411 build, fix cyclone build (replace CFLAGS in environment) 2022-02-20 22:38:12 +00:00
kub
4f6d3b2847 core vdp, optimize fifo writes 2022-02-19 21:23:54 +00:00
kub
7ce6a6d18e mcd, accelerate scale/rot rendering code 2022-02-17 19:57:37 +00:00
kub
b633247f35 mcd, accelerate scale/rot rendering code 2022-02-16 22:04:10 +00:00
kub
099f68c22a core vdp, fix regression after last commit 2022-02-15 22:15:12 +00:00
kub
3b68e5107d core vdp, fix obscure VInt bug, some more optimisation 2022-02-14 20:55:35 +00:00
kub
4fc85c80af pico, added detection by extension 2022-02-10 22:06:47 +00:00
kub
d4a08748fa mcd, improve cd status reporting 2022-02-09 23:06:10 +00:00
kub
4f3912be75 Merge remote-tracking branch 'upstream/master' 2022-02-09 22:46:26 +00:00
kub
c1d34b8adf libchdr, switch to main repo 2022-02-09 22:44:06 +00:00
kub
852f27d864 pico, improve detection 2022-02-09 22:09:23 +00:00
kub
b4e7cd1b51 libretro, update libretro-common 2022-02-09 18:42:04 +00:00
kub
8717984c12 update libchdr (libretro VFS fix) 2022-02-08 23:49:23 +00:00
kub
4496577e40 core gfx, fix sprite problem in savestate load screen 2022-02-08 22:05:00 +00:00
kub
f8395445e3 submodule update 2022-02-08 21:15:08 +00:00
kub
0004aa7cb0 build, add CFLAGS to linking for -flto 2022-02-08 20:56:01 +00:00
kub
f7741cac91 sound, fix mcd cdda (mono, resampling), type cleanup, remove minimp3 2022-02-08 20:49:43 +00:00
kub
9f1d5acdb4 sound, fix pcm/pwm handling wrt fast forward (mcd, 32x, pico) 2022-02-07 21:09:13 +00:00
kub
8eada9d64c core vdp, optimisation 2022-02-05 21:37:03 +00:00
kub
3e1b6a7746 build, fix gph build with none-eabi toolchain 2022-02-05 21:25:17 +00:00
kub
5fce11a302 build, fix incomplete clean in cyclone,musashi 2022-02-05 21:21:47 +00:00
kub
c88b729bdf libretro, improve multiplayer support 2022-01-28 17:13:04 +00:00
kub
6fa5a7498b build, fix arm64 generic build (osx) 2022-01-28 18:00:08 +00:00
kub
3244eb63ff core, fix memory leak 2022-01-28 17:58:50 +00:00
kub
73bda1add9 core, libretro vfs support 2022-01-27 22:31:09 +00:00
kub
ed7c6238b7 sh2 drc, optimisation for mips,riscv 2022-01-26 19:46:51 +00:00
kub
5daf702140 svp drc, another bugfix 2022-01-26 19:45:19 +00:00
kub
1d5885dd84 core, linux+libretro, multiplayer adaptor support 2022-01-26 19:41:19 +00:00
notaz
3672cad8d0
Merge pull request #133 from orbea/doc
Add missing licenses
2022-01-22 22:55:02 +02:00
kub
a833e78c98 svp drc, bugfixes 2022-01-22 15:07:38 +00:00
orbea
129eb5210b fame: Add html file with terms of use
Source:

http://www.emu-france.com/emulateurs/7-processeurs/82-680x0/2311-fame/

Fixes https://github.com/notaz/picodrive/issues/132
2022-01-21 18:07:36 -08:00
orbea
c6f794f276 cz80: Add missing readme.txt with license information
Source:

5edfa0d543/cpu/cz80/readme.txt
2022-01-21 18:04:04 -08:00
kub
b0fa734c87 build, release script revision, fix merge error 2022-01-20 19:32:17 +00:00
kub
464b4c171b core, fix loading save state (svp, mapper) 2022-01-20 18:26:39 +00:00
kub
a2018ca1be core, arm fix for stoneage gnu as 2022-01-20 18:24:26 +00:00
kub
8e8fa25add build, release script revision, switch arm 4.7 toolchain 2022-01-20 18:23:05 +00:00
kub
96baa875a0 core, improve save/load 2022-01-19 22:00:23 +00:00
kub
05138bbd89 sh2 drc, fixes for mips, ppc, i386 backends (mostly 64 bit related) 2022-01-19 17:09:55 +00:00
kub
b6887843e5 sh2 drc, fix riscv backend 2022-01-17 23:05:27 +00:00
kub
fc7ce3cc92 core, fix for vdp save/load regression 2022-01-07 07:32:37 +01:00
kub
14ebd37838 mcd, fix 68k interpreter idle detector for sub cpu 2022-01-06 22:37:29 +01:00
kub
dfda34424a core, improve save/load (68k cycles) 2022-01-06 22:37:29 +01:00
kub
e45908d734 vdp, improve save state handling (bg dma) 2022-01-06 22:37:28 +01:00
kub
b1a6586688 32x, improve loading save state (memory leak, 68k hang) 2022-01-06 21:35:49 +01:00
kub
cd18409722 drc, tiny x86 optimisation 2022-01-05 23:41:24 +01:00
kub
6488bec805 core, fix for vdp save/load regression 2022-01-04 17:49:24 +01:00
kub
92f7a430ca libretro, improve 32x save/load for run-ahead 2022-01-03 23:36:58 +01:00
kub
b72662e224 core, improve vdp save/load 2022-01-03 23:34:44 +01:00
kub
2cd6dfde6f sms, fix FM state save/load 2022-01-03 23:29:31 +01:00
kub
5494fde293 sound, ym2612 optimizations and fixes 2021-12-28 17:43:25 +01:00
kub
512579b031 sound, improve ym2612 accuracy (arm ASM bugfix) 2021-12-25 11:33:05 +01:00
kub
d127b3f3d5 sound, improve ym2612 accuracy (NB noticeably slower for low bitrates) 2021-12-23 00:42:11 +01:00
kub
c3fcdf3f8d 32x, more ARM asm drawing optimisations for dc mode 2021-12-19 14:40:16 +01:00
kub
2a29ca852b 32x, ARM asm drawing fixes and optimzations for dc,pp modes 2021-12-18 19:19:37 +01:00
kub
a8acecdc08 z80, DrZ80: another fix for EABI stack alignment 2021-12-14 20:20:12 +01:00
kub
ac871e1ab3 z80, DrZ80: save/restore cycles for IN/OUT, fix EABI stack alignment 2021-12-14 19:26:30 +01:00
kub
f8dba3f63a md, fix ssf2 mapping setup when loading a savestate 2021-12-12 23:48:36 +01:00
kub
ce4ae174ea platform sdl, remove some leftover debug stuff 2021-12-10 23:51:55 +01:00
kub
22a548f512 core vdp, more fixes for cpu write access and save/load 2021-12-10 23:34:03 +01:00
kub
b48d7de016 build, release script revision for new gkd 2021-12-09 22:42:54 +01:00
kub
fda7339b94 core vdp, fix FIFO DMA wait, improve save/load 2021-12-07 23:59:53 +01:00
kub
d650a7a268 core, some test code for team player and 4way play 2021-12-07 21:13:23 +01:00
kub
a54716ec19 platform, fix pad setting from configs files 2021-12-07 21:07:34 +01:00
kub
d4d2723f93 platform, fix pad not set from config when loading rom via command line 2021-12-04 22:56:33 +01:00
kub
439cf7f850 32x, improve cartridge mapping, BIOS replication 2021-11-28 22:02:11 +01:00
kub
44e4bf2b0f linux+psp, improve sw upscaling 2021-11-26 21:32:58 +01:00
kub
6890dcfafc core, improve pad compatibility (6btn, mcd32x) 2021-11-26 20:33:26 +01:00
kub
9f1b152fe2 32x, fix poll detection regression (mars check) 2021-11-26 20:30:58 +01:00
kub
1bbe9abf75 platform, improve 32x handling for h32 (all supported platforms) 2021-11-23 21:50:13 +01:00
kub
52e4a905c8 32x, add support for h32 mode rendering 2021-11-22 19:18:49 +01:00
kub
23cd73bc8f sound, fix ym2612 ladder effect, add option 2021-11-19 21:01:50 +01:00
kub
b55e4e1b2f 32x, fix DMA mem-2-mem copying for big endian 2021-11-18 22:40:19 +01:00
kub
8794ba5c8d sound, add ym2612 channel clipping, ladder effect 2021-11-17 22:32:04 +01:00
kub
55615f9c97 sms, set non-TMR images to region Japan 2021-11-15 21:26:49 +01:00
kub
fb82e166c6 core, fix libretro toolchain bug on wiiu 2021-11-15 21:25:25 +01:00
kub
404af43ddc release 1.99 2021-11-14 21:17:58 +01:00
kub
97be0d15b6 sh2 drc, fix arm32 ld/st offset for -256 2021-11-14 21:17:58 +01:00
kub
7ed05f8463 core, some type issues 2021-11-14 09:51:51 +01:00
kub
d5908845f5 sms, no nmi generation for start button on gg 2021-11-12 19:43:02 +01:00
kub
02e2ce3316 sms, fix pause button (cz80 nmi) 2021-11-12 18:35:55 +01:00
kub
b0e445ef0c sound, fix ym2612 arm assembly (ssg-eg) 2021-11-12 18:34:49 +01:00
irixxxx
50587ccd1f
Merge pull request #44 from jdgleaver/core-options-v2
(libretro) Update core options to v2 format
2021-11-11 22:50:18 +01:00
kub
b01c1ec5b8 platform, fix horizontal upscaling for 8bit renderers 2021-11-11 22:35:08 +01:00
kub
06d963c795 libretro, fix sms options 2021-11-11 22:32:12 +01:00
jdgleaver
8b2f9d02f5 (libretro) Update core options to v2 format 2021-11-11 14:45:57 +00:00
kub
e994ebeb3f platform, include current dir in bios search path 2021-11-10 23:33:18 +01:00
kub
e86583124e libretro, various fixes (input handling, aspect ratio) 2021-11-10 23:33:18 +01:00
kub
495fe1fdad platform, fix vertical scaling, aspect ratio handling (gp2x, psp) 2021-11-10 23:33:18 +01:00
kub
ace184013b core+gp2x+psp, fix handling mid-frame palette changes 2021-11-10 23:32:40 +01:00
kub
d05e2eb3d6 sms renderer, fix unaligned bg-filled tiles 2021-11-10 23:32:40 +01:00
kub
b23725dd9f platform, show Mark III as name for japanese SMS 2021-11-08 22:52:53 +01:00
kub
1a5a036eb9 core, fix typo 2021-11-08 22:48:01 +01:00
kub
5b8ff611e0 sms, fix gg always zeroing ram 2021-11-08 19:36:05 +01:00
kub
6cba1ee700 sms, set to mark iii according to tmr info 2021-11-08 18:56:49 +01:00
kub
a704c216ba mcd, fix type for memory setup (fixes LLP64 platforms) 2021-11-08 18:19:49 +01:00
kub
1510eeafd4 sound, fix buffer overrun 2021-11-06 21:01:46 +01:00
kub
1ce2b0923c sms vdp, separate SAT parsing 2021-11-06 21:00:55 +01:00
kub
f55ce7bf47 sms, add ghosting for GG LCD (generic+libretro only) 2021-11-04 20:33:28 +01:00
kub
27005bdb5f libretro, fix memory leak 2021-11-04 18:26:51 +01:00
kub
afdc2ed454 sms, autodetect for 50Hz 2021-11-02 22:44:40 +01:00
kub
f90bf8cdcf sms renderer, fix for zoomed sprites 2021-11-02 22:18:59 +01:00
kub
fe8611f9af mcd, fix pcm looping (1st sample lost) 2021-10-31 22:47:49 +01:00
kub
7eeb85beb6 sms, improve cycle counting, fix vcounter for 224/240 lines 2021-10-29 22:09:15 +02:00
kub
f9ea940fb5 sms, improved mapper support (more, menu option) 2021-10-28 21:52:44 +02:00
kub
68e7a5c1c0 sms, renderer fixes (sprite y wrap, bg in 1st col, mode 1->mode 0) 2021-10-28 21:52:44 +02:00
kub
63fb265fac libretro, add FM unit setting 2021-10-27 00:22:26 +02:00
kub
6791d84741 libretro, add FM unit setting 2021-10-26 23:36:38 +02:00
kub
1cdc3f8416 sms, some cleanup 2021-10-26 23:35:42 +02:00
kub
1bb3f2cc8d sms, fix pad TH, some BIOS init, korean 32k mapper 2021-10-25 19:44:44 +02:00
kub
fd396e58d8 sms, fix some minor vdp bugs 2021-10-25 19:40:02 +02:00
kub
0be9a92e77 z80, fix for cz80 handling of A register 2021-10-25 19:22:51 +02:00
kub
cbc2ca037a libretro, enable drc usage on WiiU 2021-10-25 18:33:43 +02:00
kub
1603058a88 sms, minor fixes (vdp mode switch, zram init) 2021-10-24 22:51:16 +02:00
kub
1c70532fc2 sms, improve compatibility (vdp reset init, pad TH/TR) 2021-10-24 12:39:29 +02:00
kub
985bbf1c03 sms, fix irq cleared in same instruction as asserted 2021-10-23 15:10:12 +02:00
kub
3039d6d852 sms, improve save/load + gg compatibility 2021-10-23 13:35:29 +02:00
kub
1c120817fe sms, improve save/load + gg compatibility 2021-10-23 12:14:46 +02:00
kub
027940e108 sound, remove hysteresis (lessens distortion, increases frequency limit) 2021-10-23 12:10:00 +02:00
kub
f0e6d1e371 psp, fix suspend/resume 2021-10-21 20:52:20 +02:00
kub
1ffc8b84f1 sms, revisit FM settings
setting moved to SMS section, default off since it crashes some games
2021-10-21 20:45:43 +02:00
kub
d0cb6cfa57 sms, minor fixes 2021-10-21 20:45:43 +02:00
kub
02d250c709 sms, fix system setting on config file reading 2021-10-20 21:33:15 +02:00
kub
8ba60e3172 sms, memory mapping changes
especially most korean games work with this
2021-10-20 21:02:52 +02:00
kub
4dbd5223b1 sms, improve vdp (mode 1, collision code cleanup) 2021-10-20 21:00:30 +02:00
kub
280bfc3ca7 sms, add system select option 2021-10-19 23:24:06 +02:00
kub
cc1547e8cd sms, improve vdp (sprite collision, hcounter latch) 2021-10-18 23:07:50 +02:00
kub
646be42e9d sms, add vdp midframe cram change handling for 8bit renderer 2021-10-17 22:50:07 +02:00
kub
e4da4fe8b9 sms, improve vdp (read buffer, h counter) 2021-10-17 22:47:18 +02:00
kub
c644ce99cd sms, fix core timing 2021-10-17 22:46:12 +02:00
kub
d2e3f475ff core, fix rendering copy buffer overlap reported from asan 2021-10-16 10:05:04 +02:00
kub
2dacba5235 sms, vdp rendering optimisation 2021-10-16 00:52:24 +02:00
kub
ae7730717c opendingux, add gg to desktop files 2021-10-15 19:39:51 +02:00
kub
2767adb5bc libretro, fix aspect ratio handling 2021-10-15 19:28:50 +02:00
kub
9b2d466aeb gp2x, fixes for sms 2021-10-15 19:27:37 +02:00
kub
a58b8f39e0 sms, vdp rendering fixes 2021-10-15 19:26:22 +02:00
kub
14cd01be51 sms, improve gg detection (zip, rom header) 2021-10-15 19:22:01 +02:00
kub
466fa07953 sms, basic gamegear support 2021-10-14 23:08:17 +02:00
kub
0df7401c02 sms vdp, add zoomed sprites, column vscroll blocking, mode 2 graphics 2021-10-08 20:24:33 +02:00
kub
032c76a3a2 sms, memory mapping improvements 2021-10-08 19:34:15 +02:00
kub
47ea630f6d z80, some cz80 cleanup 2021-10-08 18:40:06 +02:00
kub
80bf9bcce9 z80, fix sms interrupt handling in cz80 2021-10-06 19:46:39 +02:00
kub
4b3e9d92e3 sms vdp, support 224/240 line mode 2021-10-06 19:45:37 +02:00
kub
3bfee02717 z80, fix Drz80 for changed SMS banking 2021-10-04 18:18:38 +02:00
kub
3758124cb8 sms vdp, support 224/240 line mode 2021-10-04 18:03:49 +02:00
kub
b784d4a5f7 sms, improve ROM bank mapping, add some SRAM support 2021-10-03 23:59:09 +02:00
kub
15caa286fc sound, increase resolution for calculating psg sound 2021-10-02 21:31:51 +02:00
kub
86d6fb9a2f sound, increase resolution for calculating psg sound 2021-10-02 09:34:13 +02:00
kub
eb3b1f9d72 core, fix loading and mapping for images > 4MB 2021-09-30 21:57:22 +02:00
kub
6985cdd8a9 sound, fix minor clipping in psg audio 2021-09-28 21:10:02 +02:00
kub
fa0c5b4539 sound, fix psg audio (missed commit) 2021-09-25 08:38:45 +02:00
kub
af01b1b16f sound, fix psg audio 2021-09-24 18:31:19 +02:00
kub
b7697ca351 core, more superfighter mapper stuff 2021-09-22 18:44:42 +02:00
kub
e370f4d6ad core, fix sram access in ssf2 mapper
credits go to madmonkey1907 for finding this
2021-09-21 22:23:01 +02:00
kub
54e514e85d 32x, minor fix in arm renderer 2021-09-21 21:57:02 +02:00
kub
60392bf469 core, add some superfighter mappers 2021-09-21 21:52:04 +02:00
kub
0944973525 platform support, dual-licensing for upscaler code 2021-09-14 22:57:28 +02:00
kub
d1ae0810df sms, fix drawing for new scaling code 2021-09-12 10:02:01 +02:00
kub
ce79590af3 sdl, fix scaling for non-4:3 display 2021-09-11 22:18:38 +02:00
kub
0924243a53 psp, scaling revisited 2021-09-10 18:54:05 +02:00
kub
d5d1778252 sdl, complete overhaul of hardware/software scaling 2021-09-10 18:54:05 +02:00
kub
6651998e9f sound, fix for ym2612 (sonic 1 intro and others) 2021-09-10 17:58:32 +02:00
kub
ff42e515ae platform support, more upscaling basics 2021-08-20 20:03:29 +02:00
irixxxx
e1bdcf531a
Merge pull request #28 from davidgfnet/master
Fix SH2 DRC for x86 (32 bit) builds
2021-08-17 09:23:17 +02:00
David Guillen Fandos
9984a81906 Fix SH2 DRC for x86 (32 bit) builds
Turns out it doesn't work on my machine, perhaps due to newer gcc
being... unlucky! See issue #27 for more info.
Also, this fixes issue #27.
2021-08-16 18:03:34 +02:00
kub
1ea898e5d7 platform support, bugfixes, optimisations, extensions for upscaling
not yet used in the code base
2021-07-25 23:38:06 +02:00
kub
e6ecc1ef14 platform support, add upscaling code 2021-07-23 00:38:38 +02:00
kub
5c73f9d050 mcd, fix pulldowns only there if cd attached 2021-07-01 21:26:57 +02:00
kub
ef4f41a855 68k, allow cyclone execution from address 0 2021-07-01 21:21:13 +02:00
kub
bd07808352 32x, improve poll detection 2021-06-28 22:58:04 +02:00
kub
3368c27707 core, fix race condition when waiting for vsync 2021-06-28 21:58:01 +02:00
kub
e704c9b913 32x, fix comm sync (68k writing to comm area) 2021-06-28 21:43:35 +02:00
kub
8d8357dded sh2 drc, fix arm32 ld/st offset (minimum -255) 2021-06-28 21:31:32 +02:00
kub
ca8b001b7f z80, fix cz80 CPU reset (most regs not touched by reset) 2021-06-23 19:13:54 +02:00
kub
5275d43aaa sh2 drc, some small cleanups 2021-06-23 19:08:25 +02:00
kub
b5aba27c9b sh2 drc, fix constant memory address access calculation 2021-06-16 22:38:50 +02:00
kub
cbd148906d 32x, optimize poll detection 2021-06-16 22:38:50 +02:00
kub
8ee5bef7e8 sms, enable ym2413 by default 2021-06-09 22:17:34 +02:00
kub
196e2929f7 sound, improve FM output on load/resume 2021-06-09 22:15:58 +02:00
kub
4c2b81a012 68k, fix idle loop detection crash on 64 bit platforms 2021-06-08 23:11:17 +02:00
kub
df18e715ac vdp, some finetuning, cleanup 2021-06-08 22:26:24 +02:00
kub
6f9993a461 sh2 drc, fix bugs in code block management 2021-06-07 19:38:28 +02:00
kub
a5a230e0d8 sound, increase output level a bit 2021-06-03 22:06:03 +02:00
kub
cce32a34da mcd, fix pcm output level 2021-06-03 22:06:03 +02:00
kub
97916e3361 update libchdr 2021-06-03 22:06:03 +02:00
kub
05d7b88542 update cyclone (BTST #imm,Dn and ADDQ.W #imm,An timing) 2021-06-03 22:06:03 +02:00
kub
1886ac5f30 VDP DMA/CPU access timing improvements 2021-05-27 21:30:45 +02:00
kub
5e04c2f37f 68k, synchronize timing in fame and musashi (for debugging) 2021-05-25 15:02:42 +02:00
kub
b26071be31 sound, fix ym2612 output volume for keyon and level changes 2021-05-19 19:30:04 +02:00
kub
f99f0794cf sh2 interpreter, minor improvement for irq handling 2021-05-19 19:18:36 +02:00
kub
341b0ccbad 32x, minor improvement for poll detection 2021-05-19 19:15:24 +02:00
kub
fa0d0d224e sh2 drc+interpreter, minor improvement for cycle counting 2021-05-19 19:15:19 +02:00
kub
e867ec06e1 68k, fix timing for BTST #imm,Dn and ADDQ.W #imm,An in fame 2021-05-19 19:04:37 +02:00
kub
efaa5e0b04 mcd, optimizations for polling detection 2021-05-17 23:13:27 +02:00
kub
5402223466 mcd, improve polling detection 2021-05-14 23:00:04 +02:00
kub
fbebab6934 mcd, improve polling detection 2021-05-14 16:50:13 +02:00
kub
ca1b77e601 32x, drc, fix saving SH2 SR in dma 2021-05-11 22:05:57 +02:00
kub
78c2237ab8 core, big endian fix (cart sram detection) 2021-05-07 18:40:55 +02:00
kub
9b61ba715a mcd, improve polling detection 2021-05-06 22:43:31 +02:00
kub
1106272c84 ui, scaling in sdl window mode (ATM hidden) 2021-05-06 22:19:38 +02:00
kub
e08e46ba44 libretro, build change for PS3 (disable drc) 2021-05-06 22:06:04 +02:00
kub
eb36d9c7e6 mcd, fix timing for irq while polling detected 2021-05-06 21:22:31 +02:00
kub
7e77080f45 mcd, fix crash when unloading cd while playing audio 2021-05-06 21:22:31 +02:00
kub
d94eec4446 platform, fix debug hex dump if char type is signed 2021-05-06 21:22:31 +02:00
kub
d0fc3c63ba libretro, build changes for ngc/wii/wiiu 2021-04-27 21:51:44 +02:00
kub
91ea9406e2 improvements for type issues 2021-04-22 23:31:36 +02:00
kub
0d8d97f87c fixes for big endian (mostly mcd) 2021-04-22 23:31:34 +02:00
kub
567c41ff2a build, fix old dingux audio (disable static linking)wq 2021-04-21 22:36:58 +02:00
kub
64cb487928 build, tiny release script improvement 2021-04-21 22:30:58 +02:00
kub
3d7e164092 build, do arch/fpu settings only for known platforms 2021-04-21 22:05:08 +02:00
kub
083c519ec2 libretro, fix mmap replacement (content intialized to 0) 2021-04-21 22:02:36 +02:00
kub
7fe2d3d33f sh2 drc, debug stuff 2021-04-21 22:02:36 +02:00
kub
f7615fc283 sh2 drc, fix powerpc cache handling 2021-04-21 22:01:22 +02:00
kub
448b634ccc sh2 drc, fix powerpc eabi compatibility 2021-04-17 20:46:27 +02:00
kub
cc19f5a12d platform, debug dump if no disassembler support 2021-04-16 21:43:17 +02:00
kub
eba9396473 mcd, add dr_mp3 playback support 2021-04-16 21:31:30 +02:00
kub
c9a715c777 sh2 drc, debugging fixes 2021-04-16 00:27:50 +02:00
kub
09c274d4b2 68k, fix musashi support (for debugging only) 2021-04-16 00:26:23 +02:00
kub
8b55d18905 ui, fix sound filter strength not read from config file 2021-04-16 00:23:42 +02:00
kub
75aba9cc65 sh2 drc, tiny optimization for x86 2021-04-16 00:18:58 +02:00
kub
b106e5c72b libretro, add input bitmask support 2021-04-16 00:16:17 +02:00
kub
8b48f9d483 ui, fix gmenu2x control files (correct category, add chd to filelist) 2021-04-15 22:23:29 +02:00
kub
44245ef0ea libretro, build fix for ngc/wii/wiiu 2021-04-12 20:04:51 +02:00
kub
f6b8bcc701 libretro, build fix for ngc/wii/wiiu 2021-04-11 23:41:47 +02:00
kub
02d753e346 md, fix irq priority handling for H-int 2021-04-10 21:34:48 +02:00
kub
6375e62775 68k, fix unpredictable instruction in ARM asm 2021-04-10 21:34:41 +02:00
kub
6bb230c7ec 32x, scheduling optimization 2021-04-07 22:31:00 +02:00
kub
5f97951865 sh2 drc, fix optimized standard division
still turned off, needs testing and performance checks
2021-04-07 22:24:03 +02:00
kub
a95da16ae1 32x, draw, avoid some warnings 2021-04-02 22:43:06 +02:00
kub
6138c4df25 32x, fix speed regression (wt memory write optimization) 2021-04-02 21:57:08 +02:00
kub
bac4eb5136 32x, arm asm draw optimization 2021-04-02 21:54:54 +02:00
kub
2dbaa49a1a sh2 drc, x86 fix, revert 6f64058 (carry usage in NEGC/DIV1) 2021-04-02 18:45:03 +02:00
kub
b57e33123a release 1.98 2021-03-30 23:21:23 +02:00
kub
2c731fd430 add build script for release 2021-03-30 20:17:26 +02:00
kub
88a58f34a0 build improvements for gph/psp devices 2021-03-30 20:17:26 +02:00
kub
40a7d177b2 make, improve build for devices using (open)dingux 2021-03-30 20:17:18 +02:00
kub
5d3b7ae27b make, add legacy dingux and retrofw, make libavcodec optional 2021-03-27 22:29:26 +01:00
kub
a6204821d5 ui, revised menu 2021-03-26 22:52:07 +01:00
kub
2ae9324c30 update libpicofe 2021-03-26 20:25:45 +01:00
kub
63235526b8 libretro, fix missing intialization for renderer 2021-03-26 20:22:53 +01:00
kub
0995d4a764 libretro, turn of DRC for Apple OSes
JIT requires special provisions in Retroarch and possibly cores as well
2021-03-23 23:11:23 +01:00
kub
3901ab970d make, some cleanup, slightly better support for legacy dingux 2021-03-23 22:44:44 +01:00
kub
4d4bea1c5f vdp fifo, adjust latency delay 2021-03-23 22:39:17 +01:00
kub
bcc34f2cf8 attempt for DRC support for newer versions of osx/ios 2021-03-23 00:10:11 +01:00
kub
8b60ec300b attempt for DRC support for newer versions of osx/ios 2021-03-22 23:47:24 +01:00
kub
c28911fdb1 cleanup for psp 2021-03-21 23:04:14 +01:00
kub
d5bc6ef7b5 sh2 drc, debug stuff 2021-03-21 22:55:21 +01:00
kub
28f83122ec sh2 drc, don't use x29 (frame pointer) in arm64 backend 2021-03-21 22:47:56 +01:00
kub
aa8a3b65f1 sh2 drc, adjust max ld/st offset in arm backend 2021-03-21 22:41:32 +01:00
kub
a1ca8377c9 sh2 drc, fix oversize blocks ending with JSR/BSR 2021-03-16 21:42:50 +01:00
kub
6f64058800 sh2 drc, x86 backend, optimize move #0 with xor 2021-03-16 21:42:50 +01:00
kub
2d2387b293 sh2 drc, fix reading from constant memory address 2021-03-16 21:42:50 +01:00
kub
d35a929551 libretro, build fix for ps2 2021-03-12 22:10:15 +01:00
kub
ef3241d203 mcd, fix memory leaks 2021-03-12 22:09:17 +01:00
kub
fa4954281c switch to libchdr with dr_flac 2021-03-12 22:07:50 +01:00
kub
886ce067c3 core, libretro fixes for chd support 2021-03-10 23:07:25 +01:00
kub
3d1e252313 core, chd support 2021-03-09 23:01:03 +01:00
kub
4bb0b70ec8 core, chd support 2021-03-08 23:02:55 +01:00
kub
37631374df ui, revised menu and option handling, added sound filter settings 2021-03-05 22:11:39 +01:00
kub
583c4840cf vdp rendering, fix crash for sprites with negative x/y (overlooked commit) 2021-03-05 00:38:41 +01:00
kub
b010d7b4ca vdp rendering, fix crash for sprites with negative x/y 2021-03-05 00:29:52 +01:00
kub
8374e606ab core, more on chd support 2021-03-04 22:38:11 +01:00
kub
15ca715228 core, groundwork for chd support
still needs some scrutiny, and build integration is missing
2021-03-04 20:54:10 +01:00
kub
4da84f9454 fixes for big endian support (svp drc, libpicofe update) 2021-02-25 09:41:55 +01:00
kub
0c948e2c82 ui, fix for changing SDL emulation display 2021-02-25 09:41:55 +01:00
kub
57c5a5e505 add big endian platform support 2021-02-22 22:27:51 +01:00
kub
b053cb2044 preparation for retrofw and legacy opendingux support 2021-02-22 22:27:41 +01:00
kub
b1b5f9c094 fixes for platform support for PSP: show fps, notices, CD leds 2021-02-10 22:55:30 +01:00
kub
bfd6662370 fixes for platform support for PSP 2021-02-06 01:20:35 +01:00
kub
4cc0fcaf15 fixes and improvements for type issues, part 3 2021-02-06 01:14:07 +01:00
kub
832faed320 ui, fix for SDL emulation display if resolution != 320x240 2021-01-31 20:14:49 +01:00
kub
8094d3362f sh2 drc, powerpc fixes for OSX, 32 bit, cache handling 2021-01-30 09:03:01 +01:00
kub
31d08e90c8 cz80, fix flags for OUT[ID]/OT[ID]R 2021-01-22 22:33:37 +01:00
kub
bdf7761ef8 gp2x, fix for 8bit fast renderer regression 2021-01-22 10:08:20 +01:00
kub
959ea39b23 vdp renderer, partial sync 8bit fast ARM asm with C code 2021-01-21 19:09:17 +01:00
kub
1cc774814d partially revived platform support for PSP (unfinished), part 4
various fixes and improvements to screen output, menu fixes
2021-01-20 20:55:12 +01:00
kub
1e4663e1c8 sms, fix 8bit fast renderer 2021-01-20 20:55:12 +01:00
kub
bded848ccf 32x, fix BGR565 rendering 2021-01-20 20:55:12 +01:00
kub
794d463ce9 gp2x, fix to show pico ptr 2021-01-20 20:55:12 +01:00
kub
f55fb31463 vdp renderer, improvements for 8bit fast
improved 240 lines support, add setting buffer width, structural improvements
2021-01-20 20:55:12 +01:00
kub
4e0fca8142 ui, fix for gfx save/load menu bg (menubg_src != screen) 2021-01-20 19:41:14 +01:00
kub
43f79c5b41 ui, fix linux handling of 32x renderer 2021-01-20 19:39:21 +01:00
kub
1290b90de0 update libpicofe 2021-01-16 12:32:11 +01:00
kub
80bc22540a partially revived platform support for PSP (unfinished), part 3
changes to libpicofe, fixed path handling
2021-01-15 19:56:11 +01:00
kub
df6d9f93fe ui, fix battery display for platforms with screen != menuscreen 2021-01-15 15:11:25 +01:00
kub
34c7e34f77 fix for config save, custom value types not written correctly 2021-01-15 15:03:50 +01:00
kub
aa97a0a01f 32x renderer, fix for render buffers with pitch != line width, some speedup 2021-01-13 23:27:11 +01:00
kub
1dee74458b sh2 drc, fix for MIPS EABI 2021-01-13 23:14:00 +01:00
kub
6c5784f07f partially revived platform support for PSP (unfinished) #2
scaling, release generation, fixes
still not planning to make this officially supported.
2021-01-13 22:26:41 +01:00
kub
cdc6aac4c0 partially revived platform support for PSP (unfinished)
just to have a platform with an unusal screen resolution
- suspend/resume handling probably non-working
- no scaling settings
- no image generation
currently no intentions to finish this.
2021-01-10 12:13:56 +01:00
kub
f821bb7011 core, structural cleanup, fixes and improvements for type issues #2 2021-01-01 12:44:02 +01:00
kub
5ab80df952 fix building for arm arch below armv6 (gp2x, bittboy) 2020-12-29 12:10:10 +01:00
kub
15eed40550 core, fixes and improvements for type issues 2020-12-29 11:27:11 +01:00
kub
107cdd508b configure, fix for newer gcc 2020-12-29 11:15:04 +01:00
kub
2170797544 fixes for gcc warnings wrt 64 bit platforms 2020-12-29 11:13:45 +01:00
kub
30969671e5 sound, improved and optimized reimplementation of libretro lowpass filter 2020-12-23 15:51:49 +01:00
kub
b437951ade ui, separate sdl keymaps to avoid warnings with -flto 2020-12-17 23:02:17 +01:00
kub
9742bda77f SDL, better handling of 2x overlay mode 2020-12-14 21:15:32 +01:00
kub
70e9ca7191 improve mips disassembler to handle most of N32 code 2020-12-14 21:14:13 +01:00
kub
7c5227a490 vdp, fix for loading saved gfx state 2020-12-14 21:12:25 +01:00
kub
59642c52e6 32x, tentative fix for pad handling 2020-12-14 21:11:37 +01:00
kub
dc01e0b58d 32x, restore old fix for X-men 2020-12-14 21:08:35 +01:00
kub
85894ad406 cz80, improve cycle accounting 2020-12-14 21:06:24 +01:00
kub
e0d5c83fd3 32x, tiny optimization for memory access 2020-12-14 21:05:51 +01:00
kub
faedc4f1e2 mcd, add minimp3 playback support, fix libavcodec playback 2020-12-12 14:30:50 +01:00
kub
08bbe7f816 vdp rendering, fix handling of palettes 0-2 color 14 in sprite drawing 2020-12-12 14:59:09 +01:00
kub
dda72beae4 vdp, fix for 68k access timing 2020-12-12 17:29:31 +01:00
kub
1613ec6c30 vdp, kludge for z80 access 2020-12-12 17:27:30 +01:00
kub
a20300bf1e fixes for memory leaks and out of bounds memory access found by ASAN or gcc -flto 2020-12-12 14:57:56 +01:00
kub
bb70cc6e66 ui, turn cursor off in SDL (was on by default on GKD) 2020-12-12 17:31:07 +01:00
kub
7e5b769d8f libretro, improve ps2 support, switchable renderers, 32X support w/ DRC 2020-12-12 14:51:44 +01:00
kub
cd262e4cc7 libretro, add new good (aka 8bit accurate) renderer, fix 256px mode rendering 2020-12-12 14:48:15 +01:00
kub
207e5ba0ee vdp, add handling of external buffers for fast renderer 2020-12-12 14:36:54 +01:00
kub
7e382f5403 libretro, fix version string 2020-12-12 14:24:21 +01:00
kub
5d900cc4fd libretro, improve toolchain path handling for GCW0 2020-12-12 14:20:05 +01:00
kub
16b11d9171 rendering, fix bgr555 output mode
NB not done for ARM asm since no target uses bgr555
2020-12-05 15:20:15 +01:00
kub
42077979ca drc, fix libretro removing of gcc-only syntax 2020-12-05 15:17:48 +01:00
kub
512898fed1 libretro, fix apple os builds 2020-12-05 15:13:53 +01:00
kub
5735f2badf libretro, fix handling of zlib 2020-12-12 14:14:00 +01:00
kub
9511ffd153 make, improve detection of gcc 2020-12-05 22:39:08 +01:00
kub
61d76999d7 Merge from libretro/master:46902e0 for repo synchronization 2020-12-05 22:39:06 +01:00
kub
9d1ecde692 release 1.97 2020-11-23 00:30:24 +01:00
kub
efb6bc7d73 sh2 drc, fix for mapping in register cache 2020-11-23 00:24:34 +01:00
kub
1a95ce340b mcd, tentative fix for hanging 2020-11-19 00:05:22 +01:00
kub
ed9c0413ee mcd, fix for slave polling detection 2020-11-19 00:02:03 +01:00
kub
9f01ce95ae mcd, fixes for cycle accounting 2020-11-18 23:59:29 +01:00
kub
69b7b2641b ui, revise status line handling 2020-11-13 08:56:39 +01:00
kub
ae61303f86 mcd, fix SEEK status reporting 2020-11-04 18:18:24 +01:00
kub
d191afbccf switch libpicofe to local repo 2020-11-02 00:05:37 +01:00
kub
7082729e06 sh2 drc, fix sh2 reg enum usage 2020-11-01 22:55:48 +01:00
kub
fde25b40fe sh2 drc, fix PIC function calling for MIPS backend 2020-10-31 21:05:27 +01:00
kub
8c54e0dd8f fix key mapping for opendingux platforms 2020-10-27 18:10:41 +01:00
kub
8c10129faa fix for config reading of key mappings 2020-10-27 18:08:57 +01:00
kub
69c22514b0 sh2 drc, fixes for cache handling on arm and mips cpus 2020-10-27 18:05:49 +01:00
kub
e7faa8e4e1 Merge remote-tracking branch 'upstream/master' 2020-10-21 20:29:58 +02:00
kub
ac4c2eae19 libpicofe, new version for triple buffering with sdl 2020-10-14 22:51:49 +02:00
notaz
1d366b1ad9 add a hack for Decap Attack
Should delay the pull-up affect instead, but probably nothing needs
this whole thing anyway.
2020-10-13 23:19:47 +03:00
kub
6e8916bc9a sh2 drc, MIPS cache maintenance optimisation 2020-10-11 19:54:51 +02:00
kub
6131340280 sdl, enable triple buffering 2020-10-10 21:00:25 +02:00
kub
4153006fb8 sh2 drc, fix for cpu cache handling 2020-10-10 14:21:10 +02:00
kub
07a08efcfc sdl ui, fix status line artifacts if starting with rom on cmdline 2020-10-10 09:57:45 +02:00
kub
b286d66f7b sh2 drc, improve T bit propagation 2020-10-10 09:44:15 +02:00
kub
0de604b1ff sh2 drc, fix for cpu cache handling 2020-10-10 09:42:55 +02:00
kub
33cb1ab015 more rendering fixes and optimisations 2020-10-10 09:38:59 +02:00
kub
758abbebc2 ui, fix sdl flickering and status lines artifact issues 2020-10-07 20:18:37 +02:00
kub
3618d636d2 vdp rendering, fix SAT caching for high addresses >64KB 2020-10-07 20:12:23 +02:00
kub
3031ff347a vdp rendering, fix fast-forward graphics 2020-10-07 20:08:22 +02:00
kub
7165b73c26 vdp rendering, layer drawing optimisation 2020-10-07 20:07:13 +02:00
kub
71a2e205ea vdp rendering, cleanup and optimisation 2020-10-04 23:10:10 +02:00
kub
13e220715e frontend, fix scaling option handling 2020-09-30 19:34:47 +02:00
kub
47677a2ab1 vdp rendering, fixes and optimisations 2020-09-30 19:32:16 +02:00
kub
81d54be15d audio, improve YM2413 handling 2020-09-25 21:22:40 +02:00
kub
47548249a0 vdp rendering, fix window with mixed prio tiles 2020-09-25 21:19:29 +02:00
kub
30bd991f27 mcd, GenesisPlusGX bugfix 18fca13,33a43e3: report SEEK status while seeking 2020-09-23 22:28:30 +02:00
kub
1b3433bb84 mcd, fix playing wrong audio track after seek 2020-09-23 19:24:49 +02:00
kub
e721f80136 vdp, fix for gfx save/load menu bg 2020-09-21 21:02:51 +02:00
kub
8e4ab3c62c vdp rendering, fix sprite masking and interlace layer priority 2020-09-21 18:10:35 +02:00
kub
6bfa97ff78 vdp rendering, fix highlight op on shadow 2020-09-18 00:29:14 +02:00
kub
ec191db849 arm asm, tiny optimisation for 68k mem access 2020-09-18 00:28:09 +02:00
kub
627648e408 vdp, test code for 8 bit fast renderer 2020-09-18 00:27:41 +02:00
kub
bebe75ddc8 update author info 2020-09-18 00:26:34 +02:00
kub
056f101ff8 sh2 drc, standalone testing tool 2020-09-18 00:26:18 +02:00
kub
48b648070b sh2 drc, fix symbol clash 2020-09-18 00:25:54 +02:00
kub
dc56ca2ede vdp fifo, tentative fix for hanging DMA 2020-09-18 00:25:14 +02:00
kub
352479001c vdp, optimisation for 8bit renderers 2020-08-04 22:24:56 +02:00
kub
1f49b75032 SDL UI, fix SDL input and SDL window output mode for osx compile
NB for osx >= 10.14 you need SDL >= rev 13688 (ATM only available from SDL repo)
2020-08-02 23:20:09 +02:00
kub
b74303b1a7 vdp mode 4, optimisation 2020-07-29 20:47:16 +02:00
kub
a97dd5cded configure, fix for newer gcc 2020-07-29 20:41:07 +02:00
kub
3df6254bb4 Merge pull request #3 from hiroshica/hwork 2020-07-28 23:29:24 +02:00
hiroshica
95cb712a52 adding RG350 platform
squashed commits:
RG350用のキーマップを作った
opkのコマンドライン起動のエラー修正
mingw挑戦途中
2020-07-28 22:04:52 +02:00
hiroshica
2e66d031fe correcting the treatment of color number 0
squashed commits:
BGのLow/Highの描画を分離した
プライオリティを覗いて正しく描画された状態になった
2020-07-28 22:04:35 +02:00
hiroshica
a2f24bfa7b adding ym2413
squashed commits:
YM2413追加中
一通り実装したけどポートへの書き込み方が不明でまだ音が出ない
細かい修正(未テスト)
resetで初期化されるのをなんとかしたい
sound 初期化と終了を追加してみた
SN76496を参考にYM2413のアップデート方法を変更してみた
stereoフラグをアップデートサイズに変更
処理順番を整理したら音が出た
stateセーブに対応してみた
addition: Support for the Japanese Mark-III extended FM sound source unit
2020-07-28 22:04:32 +02:00
kub
7980d47767 sms mode 4, fix 8 bit renderer code 2020-07-25 23:58:57 +02:00
kub
2e5cbf5b6a audio, fix for speed regression after last commit 2020-07-17 19:26:27 +02:00
kub
6f7beab435 audio, fix sound issues in some intros 2020-07-16 19:29:49 +02:00
kub
713e3a1c5b libretro, build fixes for android 2020-07-16 19:29:34 +02:00
kub
368c918050 sh2 drc, optimize standard division insns (default off, needs more scrutiny) 2020-07-14 00:21:33 +02:00
twinaphex
48302a8a51 Buildfix 2020-07-14 00:21:33 +02:00
twinaphex
9257c0c5c8 Buildfix 2020-07-14 00:21:33 +02:00
twinaphex
1bee714816 Fix more conflicting types for prototypes 2020-07-14 00:21:33 +02:00
twinaphex
e6a52e1940 Prevent collission with PS2 SDK 2020-07-13 09:51:09 +02:00
twinaphex
182b8d01f9 Make sure function prototype signatures match, and put typedefs into
separate header file
2020-07-13 09:51:09 +02:00
kub
35984c2198 libretro, build fixes for ios 2020-07-13 09:22:56 +02:00
kub
18538b2ce8 core, keep offsets header from being build if no preprocessed asm files 2020-07-11 23:54:53 +02:00
kub
93c08696d7 libretro, build fixes 2020-07-10 23:40:35 +02:00
kub
03d5f5105c libretro, build fixes 2020-07-10 17:53:32 +02:00
kub
55c3c2b02f core, fix type issues by using stdint types 2020-07-10 09:09:52 +02:00
kub
03718e6276 libretro, build fixes 2020-07-09 23:51:39 +02:00
kub
b1ccc27109 sh2, fix for interpreter crash if drc is compiled in too 2020-07-09 08:40:35 +02:00
kub
1426b7569e sh2 drc, fix for x86_64 backend 2020-07-08 20:48:16 +02:00
kub
6b67b6aa13 libretro, more fixes and cleanups for windows and osx 2020-07-08 20:46:46 +02:00
kub
0198149a72 libretro, changes to allow for both standalone and libretro build 2020-07-08 20:14:12 +02:00
kub
e2b573c0b0 libretro, fix for windows and osx 2020-07-07 10:17:57 +02:00
kub
62c7479bb1 SDL UI, 2x overlay mode, for improved color resolution 2020-07-03 00:46:40 +02:00
kub
9279264a49 switch submodules to github and update to current version 2020-07-03 00:45:13 +02:00
kub
b29bf88c22 libretro make fix for non-arm architectures 2020-07-02 16:14:16 +02:00
kub
18c95d9f57 sh2 drc, fix for SH2 T handling in Mips/RiscV 2020-06-25 16:49:17 +02:00
kub
09cab6d27a SDL UI, preparation for 2x mode, for improved color resolution 2020-06-25 16:46:35 +02:00
kub
dd67441606 sh2 drc, optimisation for SH2 16x16 multiplication 2020-06-23 23:43:53 +02:00
kub
7a7265eea0 SDL UI, fix for CD LED display 2020-06-23 23:36:38 +02:00
kub
c815b1bc59 sh2 drc, backend 32/64 bit compatibility fixes for Mips/RiscV 2020-06-23 23:34:07 +02:00
kub
bb83412c51 vdp fifo, DMA bugfix 2020-06-21 22:32:37 +02:00
kub
8bb489470a sh2 drc, add powerpc64le backend 2020-06-19 00:14:28 +02:00
kub
dae0d04dbf sh2 drc, preparations for powerpc support 2020-06-16 18:43:45 +02:00
kub
6badfabe35 vdp rendering, bugfix for overlapping high prio sprites 2020-05-22 23:14:52 +02:00
kub
dfff48c24a release 1.96 2020-05-16 21:17:28 +02:00
kub
b718aa2d93 add copyright stuff to substantially changed files 2020-05-16 21:16:27 +02:00
kub
d39eb595bb sh2 drc: revised ARM A32 backend optimizer 2020-05-15 21:46:28 +02:00
kub
a002255e35 32x: libretro bugfix 2020-05-09 10:45:56 +02:00
kub
904fb98e6c sh2: optimisations in drc 2020-05-06 23:06:31 +02:00
kub
39c5ec3f4c audio: fix for save/load 2020-05-06 22:58:39 +02:00
kub
4321a689a5 sh2: bugfix in drc 2020-04-27 09:33:23 +02:00
kub
70aecd15b0 audio: SN76496 fixes 2020-04-24 19:08:49 +02:00
kub
fe43bdc334 32x poll detection fix 2020-04-24 19:00:41 +02:00
kub
2a2e0f890a vdp fifo, bugfix 2020-04-22 21:51:35 +02:00
kub
324bd6852e audio: add option to switch off SSG-EG 2020-04-22 21:49:48 +02:00
kub
1dbda5f894 audio: fixes and optimizations for SSG-EG 2020-04-22 21:49:48 +02:00
kub
09b96f9940 audio: improve cycle accuracy of SN76496+YM2612 2020-04-22 21:49:48 +02:00
kub
6432fb18ba 32x, small improvement for poll detection 2020-04-22 21:49:48 +02:00
kub
2eb213314a sh2, optimizations to innermost run loop 2020-04-22 21:49:02 +02:00
kub
9a02334f3a add sh2 ubc area to poll detection 2020-04-13 23:10:33 +02:00
kub
bb0488a6ba 32x pwm, tiny optimization 2020-04-13 22:22:33 +02:00
kub
74cc7aebf6 sh2 timer optimization 2020-04-13 22:20:13 +02:00
kub
7c1c9c7742 menu background fix for pal mode 2020-04-07 22:23:52 +02:00
kub
c918379137 ym2612 ARM optimisations 2020-04-07 22:07:38 +02:00
kub
b061bc166c vdp rendering, sprite caching optimization 2020-04-07 20:47:38 +02:00
kub
e8204ab27b ym2612 ARM, bug fixing and small optimizations 2020-04-02 20:33:56 +02:00
kub
86198e034b vdp DMA optimizations 2020-04-02 20:18:39 +02:00
kub
84e18560bb fix for gp2x audio regression 2020-03-30 23:54:11 +02:00
kub
02138162c4 vdp fifo speed optimization 2020-03-27 19:32:45 +01:00
kub
8d67848ddf fix for 68K cycle accounting 2020-03-27 19:27:05 +01:00
kub
61114cd8b4 vdp rendering fixes 2020-03-27 19:26:00 +01:00
kub
bd73e6eec0 vdp rendering, fix for CD (sprites from WORD RAM) 2020-03-27 19:22:19 +01:00
kub
82b3e6cf3c ARM asm, symbol visibility fix 2020-03-27 19:13:16 +01:00
kub
6dd553c7a8 vdp rendering fixes (debug register, vscroll) for overdrive 2 2020-03-19 22:51:04 +01:00
kub
c55a44a88c vdp fifo speed optimization 2020-03-14 19:52:27 +01:00
kub
20fafa7127 hvcounter table resolution reduced 2020-03-14 19:30:28 +01:00
notaz
93589da1b9
Merge pull request #106 from dinkc64/master
draw.c, DrawLayer(): impl. proper linescroll, fixes issue #56
2020-03-14 20:29:22 +02:00
kub
26643d27f2 vdp rendering improvements 2020-03-14 19:14:04 +01:00
dinkc64
ce32676eb8 draw.c, DrawLayer(): impl. proper linescroll, fixes issue #56 2020-03-13 19:26:09 -04:00
kub
2a2b4e7e88 vdp rendering, tiny improvement 2020-03-03 20:36:55 +01:00
kub
c1d0377e48 32x, small improvement for poll detector 2020-03-03 20:34:11 +01:00
kub
b6bdccb747 vdp, some small improvements 2020-03-03 20:32:38 +01:00
kub
2d84b9254c fix config file parsing for long filenames 2020-03-03 20:29:23 +01:00
kub
d38906f5ac arm asm sprite rendering: add line accidently deleted in ea431e9 2020-03-02 23:48:55 +01:00
kub
d260165ad6 ARM SVP drc revived 2020-03-02 19:40:23 +01:00
kub
ea431e9ebb vdp sprite rendering fixes 2020-03-01 18:50:55 +01:00
kub
93f41f8e16 more ARM asm sprite rendering bugfixes 2020-02-29 23:47:14 +01:00
kub
d9e12ee757 improved hi prio sprite rendering speed 2020-02-29 23:45:23 +01:00
kub
49790e265a vdp, tentative fix for save/load compatibility 2020-02-27 21:31:04 +01:00
kub
478a1164fe fix for VINT while DMA is running 2020-02-27 21:19:37 +01:00
kub
91f5fbe89b fix for EI insn in cz80 (partial revert of 43e1401) 2020-02-26 20:36:46 +01:00
kub
672b29e658 bugfix for ARM asm sprite rendering 2020-02-26 20:31:40 +01:00
kub
3c6da92ba0 vdp fifo, refined timing 2020-02-26 20:27:32 +01:00
kub
e72bc9099c vdp sprite rendering fix 2020-02-23 20:15:07 +01:00
kub
787a0af9dc vdp fifo, another revision 2020-02-23 11:33:02 +01:00
kub
25be5c52b0 vdp sprite handling improvement (SAT cache) 2020-02-16 14:10:14 +01:00
kub
daf29df963 vdp fifo, tentative fix for broken save/load 2020-02-16 14:08:48 +01:00
kub
29d99d6bb8 vdp rendering fixes 2020-02-16 13:59:58 +01:00
kub
8dc138a099 32X poll detection fix 2020-02-16 08:42:45 +01:00
kub
c64370328c fix compatibility with ancient gas 2020-02-16 08:32:29 +01:00
kub
987f079749 vdp fifo: kludge for DMA fill interrupted by CPU 2020-02-08 23:42:34 +01:00
kub
f36709e651 sh2 drc: fix for crash in generated code on x86_64 2020-02-08 15:14:04 +01:00
kub
17bd69adc6 revised VDP fifo implementation 2020-02-07 22:14:34 +01:00
kub
0f3703fd98 new hvcounter tables as per spritesmind.net threads 2020-02-07 22:13:46 +01:00
kub
4bb8111a05 regression fix for gp2x 8bit fast mode 2020-01-26 20:49:20 +01:00
kub
e1e7d1ed1c improved VRAM128K support (overdrive 2) 2020-01-26 20:48:25 +01:00
kub
1259ac4f60 VDP timing improvements 2020-01-26 20:46:21 +01:00
kub
2d5b6a66c1 added debug reg sprite plane support (fixes some issues in overdrive 2 demo) 2020-01-26 20:43:05 +01:00
kub
5f0d224e18 sprite rendering improvements for masking and limit edge cases 2020-01-26 20:40:07 +01:00
kub
7aab476859 audio fixes for overdrive demo 2020-01-26 20:12:18 +01:00
kub
43e1401008 emulator timing fixes, VDP DMA fixes, improved DAC audio 2020-01-14 23:00:44 +01:00
kub
b9bc876c9c bug fixes in drc, audio, display 2020-01-14 22:49:03 +01:00
kub
8ac9ab7fcb audio: added SSG-EG to YM2612, plus some timing changes for SN76496+YM2612 2020-01-08 00:49:13 +01:00
kub
2a942f0d41 add DC filter to sound mixer to remove potential PCM DC offset 2019-12-31 13:58:58 +01:00
kub
9090dc0f22 sh2 drc: updates from mame for ym2612 sound 2019-12-21 22:54:40 +01:00
kub
0e12269073 sh2 drc: optimize T bit handling for A64 2019-12-21 22:49:41 +01:00
kub
a5e51c16e6 sh2 drc: fix speed regression 2019-12-13 18:23:03 +01:00
kub
90b1c9db91 sh2 drc: cleanup, fix for drc crash, for mips code emitter 2019-12-11 20:39:27 +01:00
notaz
d0eab7dae8 deal with some gcc7+ warnings 2019-12-07 22:28:53 +02:00
kub
9760505eaf remove textrels with -fPIC/-fPIE (for android/ios) 2019-12-03 23:52:13 +01:00
kub
4f992bf541 sh2 drc, tentative MIPS32/64 Release 2 support 2019-12-02 22:31:14 +01:00
kub
3b0d710418 release 1.95 2019-11-27 23:05:27 +01:00
kub
57d863cb87 sh2 drc: bug fixing 2019-11-27 22:08:14 +01:00
kub
f1da0a362f sh2 drc: fixed some RISC-V bugs 2019-11-20 01:01:33 +01:00
kub
f2d19ddf2a sh2 drc, small improvements and bug fixes for code emitters 2019-11-19 21:59:44 +01:00
kub
cf0dd6ae48 sh2 drc, improved memory management 2019-11-19 21:56:50 +01:00
kub
f7a453816e sh2 drc: RISC-V (RV64IM) code emitter, some work on MIPS64 2019-11-13 21:58:48 +01:00
kub
e7ee501075 sh2 drc: RISC-V (RV64IM) code emitter, some work on MIPS64 2019-11-13 21:56:11 +01:00
kub
aaea8e3ecd sh2 drc: optimizations for MIPS code emitting 2019-11-09 10:30:57 +01:00
kub
9bd6706dca sh2 drc: moved host register assignment to code emitters, minor bugfixing 2019-11-09 10:24:52 +01:00
notaz
29cdf77cf3
Merge pull request #101 from ccawley2011/evdev
Only build evdev code on GP2X and Pandora (it's only used by them).
2019-10-19 23:15:44 +03:00
Cameron Cawley
572ab2edc4 Remove unused header 2019-10-19 17:07:12 +01:00
Cameron Cawley
95a46e3f96 Only build evdev code on GP2X and Pandora 2019-10-19 17:06:52 +01:00
kub
7e940f142e 32x, finetuning 2019-10-19 08:53:28 +02:00
kub
1fd8f98696 fix gp2x regression 2019-10-18 00:16:54 +02:00
kub
52055c13b2 sh2 drc: reorganised block mgmt code, plus some small scale optimisations 2019-10-17 21:54:37 +02:00
kub
b10a782a36 sh2 drc: bugfix in block management 2019-10-12 11:19:55 +02:00
kub
6b9ded20a0 sh2 drc: bugfix in block management 2019-10-12 11:10:28 +02:00
kub
a6c0ab7d99 sh2 drc bugfix for aarch64/mips 2019-10-12 00:26:11 +02:00
kub
e7ee7bc00a 32x, improved auto frame skip, plus new config option for max auto skip 2019-10-11 00:56:33 +02:00
kub
20d2358ab1 32x, configurable pwm irq optimization to reduce pwm irq load 2019-10-11 00:56:32 +02:00
kub
86c16afd45 32x, speed improvement 2019-10-11 00:56:26 +02:00
kub
7869213d35 sh2 drc: speed optimization and bugfixing 2019-10-11 00:51:19 +02:00
kub
c3ebe082d3 sh2 drc: fix i386 regression 2019-10-05 11:17:49 +02:00
kub
a0f5ba4067 sh2 drc: bug fixing and optimization in register cache and branch handling 2019-10-04 17:11:18 +02:00
kub
32818177bd sh2 drc: drc exit, block linking and branch handling revised (overlooked commit) 2019-09-28 17:12:56 +02:00
kub
06bc3c0693 sh2 drc: drc exit, block linking and branch handling revised 2019-09-28 16:39:26 +02:00
kub
36614252d9 sh2 drc: improved RTS call stack cache 2019-09-19 22:14:28 +02:00
kub
58a444a295 sh2 drc: rework of register cache to implement basic loop optmization 2019-09-17 23:05:56 +02:00
kub
f53e166cf4 various smallish optimizations, cleanups, and bug fixes 2019-09-17 23:05:35 +02:00
kub
fe344bd3d8 cleanup and microoptimizations in SH2 hw handling 2019-08-31 17:37:18 +02:00
kub
f740428b81 some drawing code C optimisations 2019-08-25 17:33:13 +02:00
kub
f6b4a9ca53 bug fix in comm poll fifo, and back to -O3 2019-08-22 22:57:42 +02:00
kub
e5274cc92d pff... README, 2nd try 2019-08-21 18:43:28 +02:00
kub
0f7a30ede3 configuration changes and README 2019-08-21 18:27:26 +02:00
kub
906a1d1820 cleanup config files, copyright stuff 2019-08-20 22:26:39 +02:00
kub
4f06c0df56 fix for mkoffsets without multiarch binutils 2019-08-16 17:25:23 +02:00
kub
8284ab7107 various small fixes and optimsations 2019-08-16 15:14:41 +02:00
kub
b90e104fc9 sh2 drc: add aarch64 backend for A64 2019-07-30 16:34:40 +02:00
kub
d80a5fd2ab sh2 drc: add mipsel backend for MIPS32 Release 1 (for JZ47xx) 2019-07-30 16:34:40 +02:00
kub
1747b6712d SH2 drc: register cache overhaul (bugfixing, speed, readability) 2019-07-30 16:34:40 +02:00
kub
748b8187db SH2 drc: bug fixing and small speed improvements 2019-07-30 16:34:40 +02:00
kub
1891e649e5 32X: memory access and polling bug fixes 2019-07-30 16:34:40 +02:00
kub
ee46642395 sh2 drc, x86 code emitter: use x86-64 registers R8-R15 2019-07-30 16:34:40 +02:00
kub
346153e08e 32x DMA memory copy performance optimisation 2019-07-30 16:34:40 +02:00
kub
8141d75694 sh2 drc, change utils abi to pass sh2 PC in arg0 (reduces compiled code size) 2019-07-30 16:34:40 +02:00
kub
39615f6079 sh2 drc, keep T bit in host flags as long as possible 2019-07-30 16:34:40 +02:00
kub
9e36dd0e08 add xSR/RTS call stack cache to sh2 drc 2019-07-30 16:34:40 +02:00
kub
e43998086c polling detection: communication poll fifo to avoid comm data loss 2019-07-30 16:34:40 +02:00
kub
0495df5d0c sh2 memory access improvements, revive ARM asm memory functions 2019-07-30 16:34:40 +02:00
kub
adf39a13f9 sh2 drc, register cache optimisations 2019-07-30 16:34:40 +02:00
kub
49daa9e093 sh2 drc, block management bugfixes and cleanup 2019-07-30 16:34:40 +02:00
kub
397ccdc6cf sh2 drc, add detection for in-memory polling 2019-07-30 16:34:40 +02:00
kub
213b7f42c1 sh2 drc, add loop detector, handle delay/idle loops 2019-07-30 16:34:40 +02:00
kub
e01deede1b sh2 drc, code emitter cleanup, add ARM reorder stage to reduce interlock 2019-07-30 16:34:40 +02:00
kub
aa4c4cb951 sh2 drc, make B/W read functions signed (reduces generated code size) 2019-07-30 16:34:40 +02:00
kub
ed7e915078 sh2 drc, improved constant handling and register allocator 2019-07-30 16:34:40 +02:00
kub
08626dab12 speed improvement and fixes for 32x ARM asm draw 2019-07-30 16:34:40 +02:00
kub
83bafe8e0b add literal pool to sh2 drc (for armv[456] without MOVT/W) 2019-07-30 16:34:40 +02:00
kub
47ee54b873 sh2 drc, reuse blocks if already previously compiled (speedup for Virtua *) 2019-07-30 16:34:40 +02:00
kub
d40a5af495 various small improvements and fixes 2019-07-30 16:34:40 +02:00
kub
f133766faa overhaul of translation cache and sh2 literals handling 2019-07-30 16:34:40 +02:00
kub
d760c90f3a added branch cache to sh2 drc to improve cross-tcache jump speed 2019-07-30 16:34:40 +02:00
kub
6822ba9d64 sh2 memory interface optimzations 2019-07-30 16:34:40 +02:00
kub
4f4e9bf3bd overhaul of the register cache (improves generated code by some 10+%) 2019-07-30 16:34:40 +02:00
kub
e267031a50 debug stuff, bug fixing 2019-07-30 16:34:40 +02:00
kub
ff0eaa11d9 move saving SH2 SR into memory access and do so only if needed 2019-07-30 16:34:40 +02:00
kub
9031406131 add 32bit memory access functions for SH2 2019-07-30 16:34:40 +02:00
kub
1db36a7a07 sh2 drc: sh2 addr modes generalization, more const propagation, code gen optimizations 2019-07-30 16:34:40 +02:00
kub
b804d9543b DRC: reworked scan_block (fix register usage masks, better block and literals detection) 2019-07-30 16:34:40 +02:00
kub
32feba7458 minor changes 2019-07-30 16:34:40 +02:00
kub
b1a047c926 reworked palette and buffer handling due to some 32X bugs 2019-07-30 16:34:40 +02:00
kub
23eef37f25 revamped 32X draw arm asm code 2019-07-30 16:34:40 +02:00
kub
064cc6d103 kludges for wwf raw, nfl 2019-07-30 16:34:40 +02:00
kub
122afd9d37 substituted tool to obtain target structure offsets (for asm) 2019-07-30 16:34:40 +02:00
kub
2fa02d5a63 improved sh2 clock handling, bug fixing + small improvement to drc emitters 2019-07-30 16:34:40 +02:00
kub
f5939109c4 sh2 drc host disassembler integration for gp2x 2019-07-30 16:34:40 +02:00
kub
5a5d765c23 bugfix for 32x 2019-07-30 16:34:40 +02:00
kub
ce322c1e37 bfd-less arm disassembler for gph 2019-07-30 16:34:40 +02:00
kub
c1d15f7397 config for x86 (32 bit only, for SH2 drc), add/revive profiling 2019-07-30 16:34:40 +02:00
kub
78d817c370 arm asm memory access functions for m/s68k 2019-07-30 16:34:40 +02:00
kub
e0396782f3 config templates for gp2x, caanoo, dingux either with system toolchain (open2x,gph,opendingux) or ubuntu arm(gcc 4.7 is highest possible),mips 2019-07-30 16:34:40 +02:00
kub
2c479106af arm asm syntax fixes for open2x 2019-07-30 16:34:40 +02:00
kub
340e528ff8 make gp2x mp3 playback functional (need to unpack and compile helix decoder separately in platform/common/helix) 2019-07-30 16:34:40 +02:00
kub
c79d0bb90f fix gp2x compilation (using linaro arm gcc 4.7 on ubuntu) 2019-07-30 16:34:40 +02:00
notaz
7ddd8501a7 release 1.93
just because orbea wants a release tarball
2019-01-25 02:36:25 +02:00
notaz
6ee3a0f98a
Merge pull request #85 from orbea/git
libretro: Allow setting GIT_VERSION.
2018-04-05 23:58:22 +03:00
notaz
8d40ae56f3
Merge pull request #83 from orbea/debug
Makefile: Update one more DEBUG conditional
2018-04-05 23:57:30 +03:00
orbea
cdb923c40d libretro: Allow setting GIT_VERSION. 2018-04-03 10:41:26 -07:00
orbea
c7397eda55 Makefile: Update one more DEBUG conditional 2018-04-02 16:19:10 -07:00
orbea
079bc1bf44 Makefile: Build with optimizations if DEBUG=0 2018-04-02 23:19:50 +03:00
notaz
fd587b673e ctr/3ds: attempt to improve cache flushing 2018-01-31 23:44:45 +02:00
notaz
2d2e57b2cf fix some issues with menu bg 2018-01-28 19:59:58 +02:00
notaz
0a0073dc9f fix a corner case with h-int 2018-01-28 19:13:01 +02:00
notaz
ee3c39efd2 fix DrawSpritesHiAS 2018-01-27 23:46:37 +02:00
notaz
6e05b76b6a add a header fixup 2018-01-27 20:03:13 +02:00
notaz
cf83610baa sms: improve irq handling 2018-01-27 19:41:57 +02:00
notaz
8fde2033ac 32x: implement standard/ssf2 mapper, part 2
Turns out wasn't actually hooked in.
2018-01-23 02:39:01 +02:00
notaz
310d973b9e don't spam DMA message
VR US triggers this
2018-01-21 19:03:51 +02:00
notaz
8b9dbcde38 32x: implement standard/ssf2 mapper 2018-01-21 18:57:13 +02:00
notaz
fda2f31020 drc: support ms ABI 2018-01-07 01:20:00 +02:00
notaz
48c9e01be8 improve 64bit portability
for win64 mostly
2018-01-06 21:29:59 +02:00
notaz
a0b95da112 libretro: pass required arg to VirtualProtect 2018-01-03 03:00:32 +02:00
notaz
9cdfc191b6 add a pitch variable
32x is still broken
2017-12-27 19:54:07 +02:00
notaz
88f6038d05
Merge pull request #72 from Chips-fr/master
Support latest raspberry GLES library name
2017-12-27 19:53:32 +02:00
Chips-fr
9c0ac97043 Support latest raspberry GLES library name 2017-12-25 17:38:36 +01:00
notaz
898d51a7fd drc: revive x86 dynarec, support x86-64 2017-12-12 01:45:59 +02:00
notaz
91be5ebd10 don't do idle log - it's not useful 2017-12-03 18:23:27 +02:00
notaz
98a3d79ba2 drc: arm: use movw/movt
it's about time...
2017-12-03 17:44:33 +02:00
notaz
00468b0a9b drc: do lit check before size_nolit is cleared 2017-12-03 17:44:33 +02:00
notaz
d602fd4f73 drc: ignore cache-through on smc check 2017-12-03 17:44:33 +02:00
notaz
f0ed9e38ad drc: rm overlapped block entry points
otherwise we get duplicates in hash tables
2017-12-03 17:44:33 +02:00
notaz
7e056c853a stop IdleDet from affecting save states 2017-12-02 00:10:08 +02:00
notaz
eefdb8a559 32x: improve 68k bios handling 2017-11-29 02:31:19 +02:00
notaz
6c2041fea0 32x: add other timing hacks
For sdram sync, like NJTE.
Still bad, but don't have a better solution for now (or ever?).
2017-11-28 02:25:06 +02:00
notaz
31fbc691a1 32x: remove some comm hacks
they can (and do) easily break things
2017-11-28 02:25:06 +02:00
notaz
6311a3baf5 move more globals to PicoInterface
similar reasons as before
2017-10-22 02:13:46 +03:00
notaz
075672bf9f sms: do psg like md does 2017-10-22 02:13:36 +03:00
notaz
eef77d7a8b handle 'bad' dma better 2017-10-21 00:02:38 +03:00
notaz
ee5d41a1ed pandora: mark prerelease versions
so they can live along released ones
2017-10-20 12:21:09 +03:00
notaz
35f2b65ef7 add 68k overclocking support 2017-10-20 12:21:09 +03:00
notaz
93f9619ed8 rearrange globals
scripted find/replace
gives slightly better code on ARM, less unnecessary asm,
~400 bytes saved
2017-10-20 12:21:09 +03:00
notaz
759c9d3846 pandora: fix build
Fixes: df9251536d "libretro: satisfy vita's dynarec needs in a cleaner way"
2017-10-20 12:20:59 +03:00
notaz
eaa147519f sms: more md-consistent drawing 2017-10-17 01:01:26 +03:00
notaz
1c25c32c11 sms: improve sr a bit 2017-10-17 00:53:35 +03:00
notaz
7669591e08 famec: eliminate global context ptr
saves like 25-35K of .text

current compile resource usage on i5-6600K:
            cpu  mem
gcc 5.4.0:  17.0 1.1g
clang 3.8:  1686 2.3g

FAMEC_NO_GOTOS:
gcc 5.4.0:   8.4 0.4g
clang 3.8:  20.0 0.15g
vs2008/O2: ~1800 ?
vs2008/O1:  ~720 ?
2017-10-15 03:26:48 +03:00
notaz
12f23dac6f famec: split fm68k_emulate
in FAMEC_NO_GOTOS mode at least
2017-10-15 00:45:55 +03:00
notaz
fdcfd32374 get rid of custom memcpy funcs
not used for anything important, just a maintenance burden
2017-10-14 21:28:36 +03:00
notaz
ba11a48115 fix clang build
yet another workaround for it...
2017-10-14 21:28:36 +03:00
notaz
24aab4da73 let it build on msvc
supposedly for the original XBox?
2017-10-14 21:28:24 +03:00
notaz
adb98333d7 drop draw_amips from libretro too
There's no proof it's any faster, it's only a maintenance burden.
See also 4aedc59300 .
2017-10-14 00:53:09 +03:00
notaz
e9a11abb3c drop some unnecessary inlines
apparently somebody compiles with msvc?
2017-10-14 00:53:09 +03:00
notaz
b5f5dc1fad android: make armeabi buildable 2017-10-14 00:53:09 +03:00
notaz
df9251536d libretro: satisfy vita's dynarec needs in a cleaner way 2017-10-14 00:53:09 +03:00
notaz
28a5b39232 libretro: update for core changes
also drops the broken "fps override" feature
2017-10-14 00:53:09 +03:00
notaz
a4fa71d4da libretro: drop sram clear
It's done by the core. If the core is missing something, core itself
needs to be fixed.
2017-10-14 00:53:09 +03:00
notaz
bce144211c some portability cleanups 2017-10-14 00:53:09 +03:00
notaz
7612bf90be re-import all libretro code from it's fork
Verbatim copy from https://github.com/libretro/picodrive/ commit
9ae88ef15ff00cacc3877c7ecc13b0092bab50b8 , so look there for the history
of libretro specific changes. Unfortunately there is too much noise and
divergence to merge this in a proper way.
2017-10-14 00:53:09 +03:00
iLag
126eb5f469 Fix remaining bugs and fix indentation 2017-10-14 00:53:09 +03:00
iLag
9a570a67ca Restore support for short GG cheats. 2017-10-14 00:53:09 +03:00
iLag
ed4a2193f7 Add support for Master System cheats.
notaz: drop wrong code (PicoWrite8_z80 are 68k functions, not for sms)
2017-10-14 00:53:09 +03:00
iLag
8655fd0462 Add support for single-line cheats and PAR codes.
notaz: include required header
2017-10-14 00:53:09 +03:00
David
9e38b1f0d6 Fix the lprintf method (libretro side)
The lprintf method used the format string instead of the buffer build
from va_list
2017-10-14 00:53:09 +03:00
notaz
65e4c57baa build: some clean ups 2017-10-14 00:53:09 +03:00
notaz
84162df45c build: drop function-sections
this has provoked people to do some horrible ifdeffery in libretro fork,
while the benefit is minimal, if any.
2017-10-14 00:53:09 +03:00
notaz
0bc8955485 release 1.92 2017-10-14 00:53:09 +03:00
notaz
cf07a88d6e fix cell scroll drawing 2017-10-14 00:53:08 +03:00
notaz
c041308933 fame: fix roxr
also take interrupts on exit, like other cores do
2017-10-14 00:53:08 +03:00
notaz
0e4bde9b2d rework sr
note to self:

h32 0x10A .. 0x127 0x1D2 .. 0x1FF 0x000 .. 0x109
pclk      30      |      46      |      266      = 342
hbset       0x126        ...       0x009
pclk   29  |      1   +  46    +  10    |  256
mclk   290 |           570              |  2560  = 3420
68kclk 41.4            81.4               365.7 ~= 488.5

h40 0x14A .. 0x16C 0x1C9 .. 0x1FF 0x000 .. 0x149
pclk      35      |      55      |      330      = 420
hbset       0x166        ...       0x00A
pclk   28  |      7   +  55    +  11    |  319
mclk  28*8 | 7*8   4*8+314+10+(18+11)*8 | 319*8  = 3420
68kclk  32             92                 364.5 ~= 488.5
2017-10-14 00:53:08 +03:00
notaz
22814963cc some irq hacks
notes to self (derived from Nemesis):

H32: 0x10A .. 0x127 0x1D2 .. 0x1FF 0x000 0x001
pclk       30             46          1 |0x109
mclk                 770                | 2650   = 3420
68kclk              110                   378.5 ~= 488.5

H40: 0x14A .. 0x16C 0x1C9 .. 0x1FF 0x000 0x001
pclk       35             55          1
mclk     35*8       4*8+314+10+19*8     |0x149*8
                  788                   | 2632   = 3420
68kclk           112.5                    376   ~= 488.5
2017-10-14 00:53:08 +03:00
notaz
e015ad3c1b update libpicofe 2017-10-14 00:53:08 +03:00
notaz
2b46e6c105 fix t574 reset 2017-10-14 00:53:08 +03:00
notaz
88fd63ad10 split memories away from Pico
saves ~3k of code on ARM because Pico no longer crosses ldr limit
2017-10-14 00:53:08 +03:00
notaz
e64886365d drop legacy save support
the format has been changed like 10 years ago
2017-10-14 00:53:08 +03:00
notaz
4aedc59300 drop unmaintained mips code
can always be brought back if anyone has proof it's faster
2017-10-12 02:56:11 +03:00
notaz
334f00e24e vdp timing hacks 2017-10-12 02:56:09 +03:00
notaz
3162a7104c adjust z80 timing a bit 2017-10-12 02:54:46 +03:00
notaz
ebd70cb5d9 fix various logging issues 2017-10-12 02:54:46 +03:00
notaz
9db6a54485 menu: add reset hotkey 2017-10-12 02:54:46 +03:00
notaz
e42a47e208 some more risky timing changes
But should be closer to the real thing.
Let's see what this will break...
2017-10-12 02:54:41 +03:00
notaz
8f80007bcc fix underalloc 2017-10-07 01:36:59 +03:00
notaz
d1b8bcc634 some poor timing improvement attempts 2017-10-07 01:36:59 +03:00
notaz
75b84e4b7c slightly better z80 vdp reads 2017-10-07 01:36:59 +03:00
notaz
12f89605e3 improve fast forward for cd
still broken, but a little bit better
2017-10-07 01:36:59 +03:00
notaz
5d638db094 handle frequent psg updates 2017-10-07 01:36:59 +03:00
notaz
5103774f6d sn76496: simplify writes 2017-10-07 01:36:59 +03:00
notaz
4f2cdbf551 clean up dac code a bit 2017-10-07 01:36:59 +03:00
notaz
e23f4494fb state: setup banks before CPUs on load 2017-10-07 01:36:59 +03:00
notaz
151df6adf9 simple ym2612 fixes 2017-10-07 01:36:59 +03:00
notaz
6d28fb5023 fix ym2612 asm, rework EG
this should be split, but I'm lazy
EG saves ~900 bytes
2017-10-07 01:36:59 +03:00
notaz
e0bcb7a90d some support for vdp debug reg 2017-10-03 00:41:13 +03:00
notaz
1a08dec0e0 simplify tile drawing
cuts away 1126 bytes of code on x86
2017-10-03 00:41:13 +03:00
notaz
eced019098 scroll size improvement 2017-10-03 00:41:13 +03:00
notaz
b71cbbf705 some support for 128k mode 2017-10-03 00:41:10 +03:00
notaz
b0e08dff9a allow limited z80 vdp access
lame and totally wrong timing
2017-10-03 00:40:37 +03:00
notaz
40d22a8e76 recognize the MED ssf2 header 2017-10-03 00:40:37 +03:00
notaz
f508065409 relax the bank check
there is 512K padding on load
2017-10-03 00:40:37 +03:00
notaz
c6b118c0ad fame: always update the fetch map
should just get rid of that thing, it's annoying
2017-10-03 00:40:37 +03:00
notaz
6d8782a1f9 don't miss the sprite check
DrawAllSprites depends on HighLnSpr, so prepare in DrawAllSprites was a
bad idea as lots of things may have changed
2017-10-03 00:40:37 +03:00
notaz
0c7d1ba332 some dma improvements
no idea if anything needs this, shouldn't hurt either
2017-10-03 00:40:21 +03:00
notaz
7feeb88062 make dma honour banking
I was sure I had it done before, turns out not.
2017-09-30 20:53:11 +03:00
notaz
6a47c2d4fb integrate SPI EEPROM 2017-09-30 20:53:11 +03:00
notaz
8c2137f11f import SPI EEPROM from Genesis-Plus-GX
Author: EkeEke
2017-09-30 20:53:11 +03:00
notaz
9725370321 update libpicofe 2017-09-30 20:53:11 +03:00
notaz
1dd0871f20 memory: allow SRAM word writes
Was allowing both low and high byte writes by byte, but not word,
which was stupid.
2017-09-20 23:47:09 +03:00
notaz
2b15cea82e workaround idledet breaking op test 2017-09-20 23:47:09 +03:00
notaz
c6e1e9779a 68k cores: fix bcd instructions
passing flamewing's test now
2017-09-20 23:47:09 +03:00
notaz
f6aa2456a4 famec: adjust divu timing
it's wrong, but I need it to be consistent with other cores now
2017-09-20 23:47:09 +03:00
notaz
5c5d89adbb famec: fix CHK 2017-09-20 23:47:09 +03:00
notaz
8d998330d0 famec: improve trace a bit
or break it (nobody uses it anyway), just want m68k_opcode_sizes to pass
2017-09-20 23:47:09 +03:00
notaz
a39743e315 musashi: don't generate unneeded handlers
at least move16 was incorrectly hooked up
2017-09-20 23:47:09 +03:00
notaz
e01cf375cb musashi: run same amount of cycles as other cores
for consistency
2017-09-13 01:54:10 +03:00
notaz
0104fd873b musashi: fix build on newer gcc 2017-09-13 01:54:10 +03:00
notaz
61c4e5117a 32x: skip unnecessary bios work in cd mode 2017-08-19 00:38:03 +03:00
notaz
6a5b1b362e sh2: handle some branch exceptions 2017-08-18 03:44:46 +03:00
notaz
61290a3553 drz80: drop fast_sp for compatibility
no measurable improvement in most cases anyway
2017-08-11 02:12:57 +03:00
notaz
20a10d3ed9 android: solve "text segment is not shareable"
Some asm is disabled and some performance is lost by this.
2017-08-08 02:25:37 +03:00
notaz
ae7830aae1 get some gp2x stuff out of the way for others 2017-08-06 23:22:53 +03:00
notaz
34e424aa27 remove dead code 2017-08-06 23:02:28 +03:00
notaz
98a2714234 eliminate texrels, part 3 2017-08-06 22:25:26 +03:00
notaz
6027c719ba configure: allow to override SDL_CONFIG 2017-08-06 21:21:35 +03:00
notaz
88a8088545 some fps counter cosmetics 2017-08-06 19:23:36 +03:00
notaz
99bdfd31b8 eliminate texrels (wip2) 2017-08-06 19:23:20 +03:00
notaz
ea38612fad eliminate texrels (wip) 2017-08-06 18:18:29 +03:00
notaz
bc38f4d24f remove some dead code 2017-08-06 02:22:12 +03:00
notaz
c5c5dd7132 cd: fix missed null terminator 2017-08-06 01:48:25 +03:00
notaz
14caeebcc7 fix android build 2017-08-04 01:08:17 +03:00
notaz
ad949800e4 fix a name clash with newer zlib 2017-08-04 00:36:13 +03:00
notaz
0e352905c7 fix some warnings
warning: array subscript is above array bounds [-Warray-bounds]
2017-04-17 00:50:49 +03:00
notaz
01685eefb0 fix broken error path 2017-04-17 00:50:49 +03:00
notaz
325ee167fd use system's zlib
except for libretro
github issue #45
2017-04-17 00:50:49 +03:00
notaz
b4c2331e79 get rid of the silly unzip_stream
... and just use zlib's inflate. Needed for the next commit.
2017-04-17 00:50:49 +03:00
notaz
0270424fac adjust famec flags after O2 -> O3 change 2016-01-27 02:11:16 +02:00
notaz
20347237e7 Merge pull request #37 from Chips-fr/master
Add Rpi1 and Rpi2 platform support with GLES upscaling
2016-01-27 02:06:13 +02:00
Chips-fr
8450a2f561 Add Rpi1 and Rpi2 support with GLES upscaling 2016-01-20 20:34:46 +01:00
notaz
341af486f5 Merge pull request #34 from Chips-fr/master
Enabe JIT for linux arm platform(Rpi...)
2015-10-26 23:28:44 +02:00
Chips-fr
05eb243d03 Enabe JIT for linux arm platform(Rpi...) 2015-10-25 18:19:48 +01:00
notaz
0bc48495d3 another try to reduce compiler problems with fame
also update libpicofe
2015-08-29 02:37:23 +03:00
notaz
9ddede0990 update to newer cyclone and libpicofe 2015-08-29 02:37:23 +03:00
notaz
fbba0ff6a0 make memcpy32/memset32 take void * 2015-08-29 02:37:23 +03:00
notaz
ce07c136bb Merge pull request #26 from EXL/fix_avcodec_compile_errors
Fix avcodec compile errors
2015-04-23 23:17:59 +03:00
EXL
1dfbe19da9 Fix avcodec compile errors
mp3_libavcodec.c:141:31: error: ‘CODEC_ID_MP3’ undeclared (first use in this function)
mp3_libavcodec.c:141:31: error: type of formal parameter 1 is incomplete
2015-04-21 16:32:16 +06:00
notaz
5ec48917cf Merge pull request #17 from fr500/master
fix libretro-super build
2014-08-05 02:42:01 +03:00
Andrés Suárez
f814c3f6f8 fix libretro-super build
fix libretro-super build
2014-07-30 09:24:59 -05:00
twinaphex
f9020f359c (Clang) Linker fix 2013-12-13 02:22:40 +02:00
twinaphex
1c67828540 (iOS) Add min SDK version flags 2013-12-13 02:22:37 +02:00
notaz
21299f18ad try to deal with some famec compiler issues 2013-12-07 02:03:38 +02:00
notaz
0fd6751db8 libretro: empty srm prevention hack 2013-10-13 18:46:48 +03:00
348 changed files with 75546 additions and 28014 deletions

284
.github/workflows/ci.yml vendored Normal file
View file

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

19
.github/workflows/prepare.yml vendored Normal file
View file

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

27
.gitignore vendored
View file

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

14
.gitmodules vendored
View file

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

View file

@ -4,6 +4,12 @@ Pandora, GPH device, PSP, Gizmondo ports, CPU core hacks
lots of additional coding (see changeLog).
Homepage: http://notaz.gp2x.de/
irixxxx
improvements to dynamic recompilers, 32X emulation, ARM asm, sound, VDP,
platforms (GPH, PSP, generic linux), added SG-1000 and Game Gear support,
fixed a lot of bugs (and probably added more new bugs), cleaned up stuff,
probably more that I've already forgotten.
fDave
project starter
Cyclone 68000 core and PicoDrive core itself
@ -29,7 +35,6 @@ Homepage: http://www.mame.net/
Eke-Eke
CD graphics processor and CD controller implementation (from Genesis Plus GX)
Additional thanks
-----------------
@ -53,4 +58,5 @@ Additional thanks
* Paul Cercueil for OpenDingux port.
* Inder for some graphics.
* squarepusher for some libretro fixes
* Hiroshica for support of japanese Mark-III extended YM2413 sound
* Anyone else I forgot. Let me know if it's you.

383
Makefile
View file

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

View file

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

15
README
View file

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

55
README.md Normal file
View file

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

293
configure vendored
View file

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

8345
cpu/DrZ80/drz80.S Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

@ -1 +1 @@
Subproject commit 590d780f20871b29fdc803bd2c74b046fd2d0f28
Subproject commit 3ac7cf1bdeecb60e2414980e8dc72ff092f69769

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -70,7 +70,7 @@ switch (Opcode)
OPXY(0x5c): // LD E,HX
OPXY(0x7c): // LD A,HX
zR8((Opcode >> 3) & 7) = data->B.H;
RET(5)
RET(4)
OPXY(0x45): // LD B,LX
OPXY(0x4d): // LD C,LX
@ -78,7 +78,7 @@ switch (Opcode)
OPXY(0x5d): // LD E,LX
OPXY(0x7d): // LD A,LX
zR8((Opcode >> 3) & 7) = data->B.L;
RET(5)
RET(4)
OPXY(0x60): // LD HX,B
OPXY(0x61): // LD HX,C
@ -86,7 +86,7 @@ switch (Opcode)
OPXY(0x63): // LD HX,E
OPXY(0x67): // LD HX,A
data->B.H = zR8(Opcode & 7);
RET(5)
RET(4)
OPXY(0x68): // LD LX,B
OPXY(0x69): // LD LX,C
@ -94,15 +94,15 @@ switch (Opcode)
OPXY(0x6b): // LD LX,E
OPXY(0x6f): // LD LX,A
data->B.L = zR8(Opcode & 7);
RET(5)
RET(4)
OPXY(0x65): // LD HX,LX
data->B.H = data->B.L;
RET(5)
RET(4)
OPXY(0x6c): // LD LX,HX
data->B.L = data->B.H;
RET(5)
RET(4)
OPXY(0x06): // LD B,#imm
OPXY(0x0e): // LD C,#imm
@ -113,11 +113,11 @@ switch (Opcode)
OPXY(0x26): // LD HX,#imm
data->B.H = READ_ARG();
RET(5)
RET(4)
OPXY(0x2e): // LD LX,#imm
data->B.L = READ_ARG();
RET(5)
RET(4)
OPXY(0x0a): // LD A,(BC)
goto OP_LOAD_A_mBC;
@ -194,8 +194,9 @@ switch (Opcode)
OPXY(0xc1): // POP BC
OPXY(0xd1): // POP DE
OPXY(0xf1): // POP AF
goto OP_POP_RR;
OPXY(0xf1): // POP AF
goto OP_POP_AF;
OPXY(0xe1): // POP IX
goto OP_POP;
@ -206,8 +207,9 @@ switch (Opcode)
OPXY(0xc5): // PUSH BC
OPXY(0xd5): // PUSH DE
OPXY(0xf5): // PUSH AF
goto OP_PUSH_RR;
OPXY(0xf5): // PUSH AF
goto OP_PUSH_AF;
OPXY(0xe5): // PUSH IX
goto OP_PUSH;
@ -242,12 +244,12 @@ switch (Opcode)
OPXY(0x24): // INC HX
data->B.H++;
zF = (zF & CF) | SZHV_inc[data->B.H];
RET(5)
RET(4)
OPXY(0x2c): // INC LX
data->B.L++;
zF = (zF & CF) | SZHV_inc[data->B.L];
RET(5)
RET(4)
OPXY(0x34): // INC (IX+o)
adr = data->W + (INT8)READ_ARG();
@ -268,12 +270,12 @@ switch (Opcode)
OPXY(0x25): // DEC HX
data->B.H--;
zF = (zF & CF) | SZHV_dec[data->B.H];
RET(5)
RET(4)
OPXY(0x2d): // DEC LX
data->B.L--;
zF = (zF & CF) | SZHV_dec[data->B.L];
RET(5)
RET(4)
OPXY(0x35): // DEC (IX+o)
adr = data->W + (INT8)READ_ARG();
@ -296,12 +298,10 @@ switch (Opcode)
OPXY(0x84): // ADD A,HX
val = data->B.H;
USE_CYCLES(1)
goto OP_ADD;
OPXY(0x85): // ADD A,LX
val = data->B.L;
USE_CYCLES(1)
goto OP_ADD;
OPXY(0x86): // ADD A,(IX+o)
@ -326,12 +326,10 @@ switch (Opcode)
OPXY(0x8c): // ADC A,HX
val = data->B.H;
USE_CYCLES(1)
goto OP_ADC;
OPXY(0x8d): // ADC A,LX
val = data->B.L;
USE_CYCLES(1)
goto OP_ADC;
OPXY(0x8e): // ADC A,(IX+o)
@ -356,12 +354,10 @@ switch (Opcode)
OPXY(0x94): // SUB HX
val = data->B.H;
USE_CYCLES(1)
goto OP_SUB;
OPXY(0x95): // SUB LX
val = data->B.L;
USE_CYCLES(1)
goto OP_SUB;
OPXY(0x96): // SUB (IX+o)
@ -386,12 +382,10 @@ switch (Opcode)
OPXY(0x9c): // SBC A,HX
val = data->B.H;
USE_CYCLES(1)
goto OP_SBC;
OPXY(0x9d): // SBC A,LX
val = data->B.L;
USE_CYCLES(1)
goto OP_SBC;
OPXY(0x9e): // SBC A,(IX+o)
@ -416,12 +410,10 @@ switch (Opcode)
OPXY(0xbc): // CP HX
val = data->B.H;
USE_CYCLES(1)
goto OP_CP;
OPXY(0xbd): // CP LX
val = data->B.L;
USE_CYCLES(1)
goto OP_CP;
OPXY(0xbe): // CP (IX+o)
@ -446,12 +438,10 @@ switch (Opcode)
OPXY(0xa4): // AND HX
val = data->B.H;
USE_CYCLES(1)
goto OP_AND;
OPXY(0xa5): // AND LX
val = data->B.L;
USE_CYCLES(1)
goto OP_AND;
OPXY(0xa6): // AND (IX+o)
@ -476,12 +466,10 @@ switch (Opcode)
OPXY(0xac): // XOR HX
val = data->B.H;
USE_CYCLES(1)
goto OP_XOR;
OPXY(0xad): // XOR LX
val = data->B.L;
USE_CYCLES(1)
goto OP_XOR;
OPXY(0xae): // XOR (IX+o)
@ -506,12 +494,10 @@ switch (Opcode)
OPXY(0xb4): // OR HX
val = data->B.H;
USE_CYCLES(1)
goto OP_OR;
OPXY(0xb5): // OR LX
val = data->B.L;
USE_CYCLES(1)
goto OP_OR;
OPXY(0xb6): // OR (IX+o)

View file

@ -48,11 +48,7 @@
#define READ_OP() GET_OP(); PC++
#define READ_ARG() (*(UINT8 *)PC++)
#if CZ80_LITTLE_ENDIAN
#define READ_ARG16() (*(UINT8 *)PC | (*(UINT8 *)(PC + 1) << 8)); PC += 2
#else
#define READ_ARG16() (*(UINT8 *)(PC + 1) | (*(UINT8 *)PC << 8)); PC += 2
#endif
//#ifndef BUILD_CPS1PSP
//#define READ_MEM8(A) memory_region_cpu2[(A)]
@ -63,17 +59,13 @@
#define READ_MEM8(A) CPU->Read_Byte(A)
#endif
//#endif
#if CZ80_LITTLE_ENDIAN
#define READ_MEM16(A) (READ_MEM8(A) | (READ_MEM8((A) + 1) << 8))
#else
#define READ_MEM16(A) ((READ_MEM8(A) << 8) | READ_MEM8((A) + 1))
#endif
#if PICODRIVE_HACKS
#define WRITE_MEM8(A, D) { \
unsigned short a = A; \
unsigned char d = D; \
unsigned long v = z80_write_map[a >> Z80_MEM_SHIFT]; \
uptr v = z80_write_map[a >> Z80_MEM_SHIFT]; \
if (map_flag_set(v)) \
((z80_write_f *)(v << 1))(a, d); \
else \
@ -82,11 +74,7 @@
#else
#define WRITE_MEM8(A, D) CPU->Write_Byte(A, D);
#endif
#if CZ80_LITTLE_ENDIAN
#define WRITE_MEM16(A, D) { WRITE_MEM8(A, D); WRITE_MEM8((A) + 1, (D) >> 8); }
#else
#define WRITE_MEM16(A, D) { WRITE_MEM8((A) + 1, D); WRITE_MEM8(A, (D) >> 8); }
#endif
#define PUSH_16(A) { UINT32 sp; zSP -= 2; sp = zSP; WRITE_MEM16(sp, A); }
#define POP_16(A) { UINT32 sp; sp = zSP; A = READ_MEM16(sp); zSP = sp + 2; }
@ -94,36 +82,36 @@
#define IN(A) CPU->IN_Port(A)
#define OUT(A, D) CPU->OUT_Port(A, D)
#define CHECK_INT \
if (zIFF1) \
{ \
UINT32 IntVect; \
\
if (CPU->IRQState == HOLD_LINE) \
CPU->IRQState = CLEAR_LINE; \
\
CPU->HaltState = 0; \
zIFF1 = zIFF2 = 0; \
IntVect = CPU->Interrupt_Callback(CPU->IRQLine); \
\
PUSH_16(zRealPC) \
\
if (zIM == 2) \
{ \
IntVect = (IntVect & 0xff) | (zI << 8); \
PC = READ_MEM16(IntVect); \
CPU->ExtraCycles += 17; \
} \
else if (zIM == 1) \
{ \
PC = 0x38; \
CPU->ExtraCycles += 13; \
} \
else \
{ \
PC = IntVect & 0x38; \
CPU->ExtraCycles += 13; \
} \
\
SET_PC(PC) \
#define CHECK_INT \
if (zIFF1) \
{ \
UINT32 IntVect; \
\
if (CPU->IRQState == HOLD_LINE) \
CPU->IRQState = CLEAR_LINE; \
\
CPU->Status &= ~(CZ80_HALTED|CZ80_HAS_INT); \
zIFF1 = zIFF2 = 0; \
IntVect = CPU->Interrupt_Callback(CPU->IRQLine); \
\
PUSH_16(zRealPC) \
\
if (zIM == 2) \
{ \
IntVect = (IntVect & 0xff) | (zI << 8); \
PC = READ_MEM16(IntVect); \
CPU->ExtraCycles += 17; \
} \
else if (zIM == 1) \
{ \
PC = 0x38; \
CPU->ExtraCycles += 13; \
} \
else \
{ \
PC = IntVect & 0x38; \
CPU->ExtraCycles += 13; \
} \
\
SET_PC(PC) \
}

246
cpu/cz80/readme.txt Normal file
View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

1432
cpu/drc/emit_arm64.c Normal file

File diff suppressed because it is too large Load diff

1969
cpu/drc/emit_mips.c Normal file

File diff suppressed because it is too large Load diff

1844
cpu/drc/emit_ppc.c Normal file

File diff suppressed because it is too large Load diff

1701
cpu/drc/emit_riscv.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

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

1128
cpu/fame/fame.html Normal file

File diff suppressed because it is too large Load diff

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
#include "../sh2.h"
#ifdef DRC_CMP
#include "../compiler.c"
#include "../compiler.h"
#define BUSY_LOOP_HACKS 0
#else
#define BUSY_LOOP_HACKS 1
@ -9,34 +9,36 @@
// MAME types
#ifndef INT8
typedef signed char INT8;
typedef signed short INT16;
typedef signed int INT32;
typedef unsigned int UINT32;
typedef unsigned short UINT16;
typedef unsigned char UINT8;
typedef s8 INT8;
typedef s16 INT16;
typedef s32 INT32;
typedef u32 UINT32;
typedef u16 UINT16;
typedef u8 UINT8;
#endif
#ifdef DRC_SH2
// this nasty conversion is needed for drc-expecting memhandlers
#define MAKE_READFUNC(name, cname) \
static inline unsigned int name(SH2 *sh2, unsigned int a) \
static __inline unsigned int name(SH2 *sh2, unsigned int a) \
{ \
unsigned int ret; \
sh2->sr |= sh2->icount << 12; \
sh2->sr |= (sh2->icount << 12) | (sh2->no_polling); \
ret = cname(a, sh2); \
sh2->icount = (signed int)sh2->sr >> 12; \
sh2->no_polling = (sh2->sr & SH2_NO_POLLING); \
sh2->sr &= 0x3f3; \
return ret; \
}
#define MAKE_WRITEFUNC(name, cname) \
static inline void name(SH2 *sh2, unsigned int a, unsigned int d) \
static __inline void name(SH2 *sh2, unsigned int a, unsigned int d) \
{ \
sh2->sr |= sh2->icount << 12; \
sh2->sr |= (sh2->icount << 12) | (sh2->no_polling); \
cname(a, d, sh2); \
sh2->icount = (signed int)sh2->sr >> 12; \
sh2->no_polling = (sh2->sr & SH2_NO_POLLING); \
sh2->sr &= 0x3f3; \
}
@ -121,13 +123,25 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles)
if (sh2->delay)
{
sh2->ppc = sh2->delay;
opcode = RW(sh2, sh2->delay);
opcode = (UINT32)(UINT16)RW(sh2, sh2->delay);
// TODO: more branch types
if ((opcode >> 13) == 5) { // BRA/BSR
sh2->r[15] -= 4;
WL(sh2, sh2->r[15], sh2->sr);
sh2->r[15] -= 4;
WL(sh2, sh2->r[15], sh2->pc);
sh2->pc = RL(sh2, sh2->vbr + 6 * 4);
sh2->icount -= 5;
opcode = 9; // NOP
}
sh2->pc -= 2;
}
else
{
sh2->ppc = sh2->pc;
opcode = RW(sh2, sh2->pc);
opcode = (UINT32)(UINT16)RW(sh2, sh2->pc);
}
sh2->delay = 0;
@ -155,14 +169,16 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles)
sh2->icount--;
if (sh2->test_irq && !sh2->delay && sh2->pending_level > ((sh2->sr >> 4) & 0x0f))
if (sh2->test_irq && !sh2->delay)
{
int level = sh2->pending_level;
int vector = sh2->irq_callback(sh2, level);
sh2_do_irq(sh2, level, vector);
if (level > ((sh2->sr >> 4) & 0x0f))
{
int vector = sh2->irq_callback(sh2, level);
sh2_do_irq(sh2, level, vector);
}
sh2->test_irq = 0;
}
}
while (sh2->icount > 0 || sh2->delay); /* can't interrupt before delay */
@ -202,14 +218,14 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles)
if (sh2->pc < *base_pc || sh2->pc >= *end_pc) {
*base_pc = sh2->pc;
scan_block(*base_pc, sh2->is_slave,
op_flags, end_pc, NULL);
op_flags, end_pc, NULL, NULL);
}
if ((op_flags[(sh2->pc - *base_pc) / 2]
& OF_BTARGET) || sh2->pc == *base_pc
|| pc_expect != sh2->pc) // branched
{
pc_expect = sh2->pc;
if (sh2->icount < 0)
if (sh2->icount <= 0)
break;
}
@ -220,13 +236,13 @@ int sh2_execute_interpreter(SH2 *sh2, int cycles)
if (sh2->delay)
{
sh2->ppc = sh2->delay;
opcode = RW(sh2, sh2->delay);
opcode = (UINT32)(UINT16)RW(sh2, sh2->delay);
sh2->pc -= 2;
}
else
{
sh2->ppc = sh2->pc;
opcode = RW(sh2, sh2->pc);
opcode = (UINT32)(UINT16)RW(sh2, sh2->pc);
}
sh2->delay = 0;

View file

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

View file

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

View file

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

View file

@ -1,18 +1,19 @@
/*
* PicoDrive
* (C) notaz, 2009,2010,2013
* (C) irixxxx, 2019-2024
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*/
#include "../pico_int.h"
#include "../sound/ym2612.h"
#include "../../cpu/sh2/compiler.h"
#include <cpu/sh2/compiler.h>
struct Pico32x Pico32x;
SH2 sh2s[2];
#define SH2_IDLE_STATES (SH2_STATE_CPOLL|SH2_STATE_VPOLL|SH2_STATE_SLEEP)
#define SH2_IDLE_STATES (SH2_STATE_CPOLL|SH2_STATE_VPOLL|SH2_STATE_RPOLL|SH2_STATE_SLEEP)
static int REGPARM(2) sh2_irq_cb(SH2 *sh2, int level)
{
@ -30,38 +31,43 @@ static int REGPARM(2) sh2_irq_cb(SH2 *sh2, int level)
}
// MUST specify active_sh2 when called from sh2 memhandlers
void p32x_update_irls(SH2 *active_sh2, int m68k_cycles)
void p32x_update_irls(SH2 *active_sh2, unsigned int m68k_cycles)
{
int irqs, mlvl = 0, slvl = 0;
int mrun, srun;
if ((Pico32x.regs[0] & (P32XS_nRES|P32XS_ADEN)) != (P32XS_nRES|P32XS_ADEN))
return;
if (active_sh2 != NULL)
m68k_cycles = sh2_cycles_done_m68k(active_sh2);
// find top bit = highest irq number (0 <= irl <= 14/2) by binary search
// msh2
irqs = Pico32x.sh2irqs | Pico32x.sh2irqi[0];
while ((irqs >>= 1))
mlvl++;
mlvl *= 2;
irqs = Pico32x.sh2irqi[0];
if (irqs >= 0x10) mlvl += 8, irqs >>= 4;
if (irqs >= 0x04) mlvl += 4, irqs >>= 2;
if (irqs >= 0x02) mlvl += 2, irqs >>= 1;
// ssh2
irqs = Pico32x.sh2irqs | Pico32x.sh2irqi[1];
while ((irqs >>= 1))
slvl++;
slvl *= 2;
irqs = Pico32x.sh2irqi[1];
if (irqs >= 0x10) slvl += 8, irqs >>= 4;
if (irqs >= 0x04) slvl += 4, irqs >>= 2;
if (irqs >= 0x02) slvl += 2, irqs >>= 1;
mrun = sh2_irl_irq(&msh2, mlvl, active_sh2 == &msh2);
mrun = sh2_irl_irq(&msh2, mlvl, msh2.state & SH2_STATE_RUN);
if (mrun) {
p32x_sh2_poll_event(&msh2, SH2_IDLE_STATES, m68k_cycles);
if (active_sh2 == &msh2)
sh2_end_run(active_sh2, 1);
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_IDLE_STATES & ~SH2_STATE_SLEEP, m68k_cycles);
if (msh2.state & SH2_STATE_RUN)
sh2_end_run(&msh2, 0);
}
srun = sh2_irl_irq(&ssh2, slvl, active_sh2 == &ssh2);
srun = sh2_irl_irq(&ssh2, slvl, ssh2.state & SH2_STATE_RUN);
if (srun) {
p32x_sh2_poll_event(&ssh2, SH2_IDLE_STATES, m68k_cycles);
if (active_sh2 == &ssh2)
sh2_end_run(active_sh2, 1);
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_IDLE_STATES & ~SH2_STATE_SLEEP, m68k_cycles);
if (ssh2.state & SH2_STATE_RUN)
sh2_end_run(&ssh2, 0);
}
elprintf(EL_32X, "update_irls: m %d/%d, s %d/%d", mlvl, mrun, slvl, srun);
@ -70,16 +76,17 @@ void p32x_update_irls(SH2 *active_sh2, int m68k_cycles)
// the mask register is inconsistent, CMD is supposed to be a mask,
// while others are actually irq trigger enables?
// TODO: test on hw..
void p32x_trigger_irq(SH2 *sh2, int m68k_cycles, unsigned int mask)
void p32x_trigger_irq(SH2 *sh2, unsigned int m68k_cycles, unsigned int mask)
{
Pico32x.sh2irqs |= mask & P32XI_VRES;
Pico32x.sh2irqi[0] |= mask & P32XI_VRES;
Pico32x.sh2irqi[1] |= mask & P32XI_VRES;
Pico32x.sh2irqi[0] |= mask & (Pico32x.sh2irq_mask[0] << 3);
Pico32x.sh2irqi[1] |= mask & (Pico32x.sh2irq_mask[1] << 3);
p32x_update_irls(sh2, m68k_cycles);
}
void p32x_update_cmd_irq(SH2 *sh2, int m68k_cycles)
void p32x_update_cmd_irq(SH2 *sh2, unsigned int m68k_cycles)
{
if ((Pico32x.sh2irq_mask[0] & 2) && (Pico32x.regs[2 / 2] & 1))
Pico32x.sh2irqi[0] |= P32XI_CMD;
@ -98,13 +105,21 @@ void Pico32xStartup(void)
{
elprintf(EL_STATUS|EL_32X, "32X startup");
PicoIn.AHW |= PAHW_32X;
// TODO: OOM handling
PicoAHW |= PAHW_32X;
sh2_init(&msh2, 0, &ssh2);
msh2.irq_callback = sh2_irq_cb;
sh2_init(&ssh2, 1, &msh2);
ssh2.irq_callback = sh2_irq_cb;
if (Pico32xMem == NULL) {
Pico32xMem = plat_mmap(0x06000000, sizeof(*Pico32xMem), 0, 0);
if (Pico32xMem == NULL) {
elprintf(EL_STATUS, "OOM");
return;
}
memset(Pico32xMem, 0, sizeof(struct Pico32xMem));
sh2_init(&msh2, 0, &ssh2);
msh2.irq_callback = sh2_irq_cb;
sh2_init(&ssh2, 1, &msh2);
ssh2.irq_callback = sh2_irq_cb;
}
PicoMemSetup32x();
p32x_pwm_ctl_changed();
p32x_timers_recalc();
@ -115,13 +130,29 @@ void Pico32xStartup(void)
if (!Pico.m.pal)
Pico32x.vdp_regs[0] |= P32XV_nPAL;
else
Pico32x.vdp_regs[0] &= ~P32XV_nPAL;
rendstatus_old = -1;
Pico32xPrepare();
emu_32x_startup();
}
void Pico32xShutdown(void)
{
Pico32x.sh2_regs[0] &= ~P32XS2_ADEN;
rendstatus_old = -1;
PicoIn.AHW &= ~PAHW_32X;
if (PicoIn.AHW & PAHW_MCD)
PicoMemSetupCD();
else
PicoMemSetup();
emu_32x_startup();
}
#define HWSWAP(x) (((x) << 16) | ((x) >> 16))
void p32x_reset_sh2s(void)
{
elprintf(EL_32X, "sh2 reset");
@ -134,28 +165,30 @@ void p32x_reset_sh2s(void)
// if we don't have BIOS set, perform it's work here.
// MSH2
if (p32x_bios_m == NULL) {
unsigned int idl_src, idl_dst, idl_size; // initial data load
unsigned int vbr;
// initial data
idl_src = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d4)) & ~0xf0000000;
idl_dst = HWSWAP(*(unsigned int *)(Pico.rom + 0x3d8)) & ~0xf0000000;
idl_size= HWSWAP(*(unsigned int *)(Pico.rom + 0x3dc));
if (idl_size > Pico.romsize || idl_src + idl_size > Pico.romsize ||
idl_size > 0x40000 || idl_dst + idl_size > 0x40000 || (idl_src & 3) || (idl_dst & 3)) {
elprintf(EL_STATUS|EL_ANOMALY, "32x: invalid initial data ptrs: %06x -> %06x, %06x",
idl_src, idl_dst, idl_size);
}
else
memcpy(Pico32xMem->sdram + idl_dst, Pico.rom + idl_src, idl_size);
// GBR/VBR
vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3e8));
sh2_set_gbr(0, 0x20004000);
sh2_set_vbr(0, vbr);
// checksum and M_OK
Pico32x.regs[0x28 / 2] = *(unsigned short *)(Pico.rom + 0x18e);
if (!Pico.m.ncart_in) { // copy IDL from cartridge
unsigned int idl_src, idl_dst, idl_size; // initial data load
unsigned int vbr;
// initial data
idl_src = CPU_BE2(*(u32 *)(Pico.rom + 0x3d4)) & ~0xf0000000;
idl_dst = CPU_BE2(*(u32 *)(Pico.rom + 0x3d8)) & ~0xf0000000;
idl_size= CPU_BE2(*(u32 *)(Pico.rom + 0x3dc));
// copy in guest memory space
idl_src += 0x2000000;
idl_dst += 0x6000000;
while (idl_size >= 4) {
p32x_sh2_write32(idl_dst, p32x_sh2_read32(idl_src, &msh2), &msh2);
idl_src += 4, idl_dst += 4, idl_size -= 4;
}
// VBR
vbr = CPU_BE2(*(u32 *)(Pico.rom + 0x3e8));
sh2_set_vbr(0, vbr);
// checksum and M_OK
Pico32x.regs[0x28 / 2] = *(u16 *)(Pico.rom + 0x18e);
}
// program will set M_OK
}
@ -164,7 +197,7 @@ void p32x_reset_sh2s(void)
unsigned int vbr;
// GBR/VBR
vbr = HWSWAP(*(unsigned int *)(Pico.rom + 0x3ec));
vbr = CPU_BE2(*(u32 *)(Pico.rom + 0x3ec));
sh2_set_gbr(1, 0x20004000);
sh2_set_vbr(1, vbr);
// program will set S_OK
@ -175,10 +208,6 @@ void p32x_reset_sh2s(void)
void Pico32xInit(void)
{
if (msh2.mult_m68k_to_sh2 == 0 || msh2.mult_sh2_to_m68k == 0)
Pico32xSetClocks(PICO_MSH2_HZ, 0);
if (ssh2.mult_m68k_to_sh2 == 0 || ssh2.mult_sh2_to_m68k == 0)
Pico32xSetClocks(0, PICO_MSH2_HZ);
}
void PicoPower32x(void)
@ -186,88 +215,106 @@ void PicoPower32x(void)
memset(&Pico32x, 0, sizeof(Pico32x));
Pico32x.regs[0] = P32XS_REN|P32XS_nRES; // verified
Pico32x.regs[0x10/2] = 0xffff;
Pico32x.vdp_regs[0x0a/2] = P32XV_VBLK|P32XV_PEN;
}
void PicoUnload32x(void)
{
if (Pico32xMem != NULL)
plat_munmap(Pico32xMem, sizeof(*Pico32xMem));
Pico32xMem = NULL;
if (PicoIn.AHW & PAHW_32X)
Pico32xShutdown();
sh2_finish(&msh2);
sh2_finish(&ssh2);
PicoAHW &= ~PAHW_32X;
if (Pico32xMem != NULL)
plat_munmap(Pico32xMem, sizeof(*Pico32xMem));
Pico32xMem = NULL;
}
void PicoReset32x(void)
{
if (PicoAHW & PAHW_32X) {
if (PicoIn.AHW & PAHW_32X) {
p32x_trigger_irq(NULL, SekCyclesDone(), P32XI_VRES);
p32x_sh2_poll_event(&msh2, SH2_IDLE_STATES, 0);
p32x_sh2_poll_event(&ssh2, SH2_IDLE_STATES, 0);
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_IDLE_STATES, SekCyclesDone());
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_IDLE_STATES, SekCyclesDone());
p32x_pwm_ctl_changed();
p32x_timers_recalc();
}
}
static void p32x_start_blank(void)
static void p32x_render_frame(void)
{
if (Pico32xDrawMode != PDM32X_OFF && !PicoSkipFrame) {
if (Pico32xDrawMode != PDM32X_OFF && !PicoIn.skipFrame) {
int offs, lines;
pprof_start(draw);
offs = 8; lines = 224;
if ((Pico.video.reg[1] & 8) && !(PicoOpt & POPT_ALT_RENDERER)) {
if (Pico.video.reg[1] & 8) {
offs = 0;
lines = 240;
}
// XXX: no proper handling of 32col mode..
if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0 && // 32x not blanking
(Pico.video.reg[12] & 1) && // 40col mode
(PicoDrawMask & PDRAW_32X_ON))
(!(Pico.video.debug_p & PVD_KILL_32X)))
{
int md_bg = Pico.video.reg[7] & 0x3f;
// we draw full layer (not line-by-line)
PicoDraw32xLayer(offs, lines, md_bg);
}
else if (Pico32xDrawMode != PDM32X_32X_ONLY)
else if (Pico32xDrawMode == PDM32X_BOTH)
PicoDraw32xLayerMdOnly(offs, lines);
pprof_end(draw);
}
}
static void p32x_start_blank(void)
{
// enter vblank
Pico32x.vdp_regs[0x0a/2] |= P32XV_VBLK|P32XV_PEN;
// FB swap waits until vblank
if ((Pico32x.vdp_regs[0x0a/2] ^ Pico32x.pending_fb) & P32XV_FS) {
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_FS;
Pico32x.vdp_regs[0x0a/2] |= Pico32x.pending_fb;
Pico32xSwapDRAM(Pico32x.pending_fb ^ 1);
Pico32x.vdp_regs[0x0a/2] ^= P32XV_FS;
Pico32xSwapDRAM(Pico32x.pending_fb ^ P32XV_FS);
}
p32x_trigger_irq(NULL, SekCyclesDone(), P32XI_VINT);
p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, 0);
p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, 0);
p32x_trigger_irq(NULL, Pico.t.m68c_aim, P32XI_VINT);
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
}
void p32x_schedule_hint(SH2 *sh2, int m68k_cycles)
static void p32x_end_blank(void)
{
// end vblank
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_VBLK; // get out of vblank
if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0) // no forced blanking
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_PEN; // no palette access
if (!(Pico32x.sh2_regs[0] & 0x80)) {
// NB must precede VInt per hw manual, min 4 SH-2 cycles to pass Mars Check
Pico32x.hint_counter = (int)(-1.5*0x10);
p32x_schedule_hint(NULL, Pico.t.m68c_aim);
}
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, Pico.t.m68c_aim);
}
void p32x_schedule_hint(SH2 *sh2, unsigned int m68k_cycles)
{
// rather rough, 32x hint is useless in practice
int after;
if (!((Pico32x.sh2irq_mask[0] | Pico32x.sh2irq_mask[1]) & 4))
return; // nobody cares
// note: when Pico.m.scanline is 224, SH2s might
// still be at scanline 93 (or so)
if (!(Pico32x.sh2_regs[0] & 0x80) && Pico.m.scanline > 224)
if (!(Pico32x.sh2_regs[0] & 0x80) && (Pico.video.status & PVS_VB2))
return;
after = (Pico32x.sh2_regs[4 / 2] + 1) * 488;
Pico32x.hint_counter += (Pico32x.sh2_regs[4 / 2] + 1) * (int)(488.5*0x10);
after = Pico32x.hint_counter >> 4;
Pico32x.hint_counter &= 0xf;
if (sh2 != NULL)
p32x_event_schedule_sh2(sh2, P32X_EVENT_HINT, after);
else
@ -278,8 +325,8 @@ void p32x_schedule_hint(SH2 *sh2, int m68k_cycles)
static void fillend_event(unsigned int now)
{
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_nFEN;
p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, now);
p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, now);
p32x_sh2_poll_event(msh2.poll_addr, &msh2, SH2_STATE_VPOLL, now);
p32x_sh2_poll_event(ssh2.poll_addr, &ssh2, SH2_STATE_VPOLL, now);
}
static void hint_event(unsigned int now)
@ -294,9 +341,9 @@ typedef void (event_cb)(unsigned int now);
unsigned int p32x_event_times[P32X_EVENT_COUNT];
static unsigned int event_time_next;
static event_cb *p32x_event_cbs[P32X_EVENT_COUNT] = {
[P32X_EVENT_PWM] = p32x_pwm_irq_event,
[P32X_EVENT_FILLEND] = fillend_event,
[P32X_EVENT_HINT] = hint_event,
p32x_pwm_irq_event, // P32X_EVENT_PWM
fillend_event, // P32X_EVENT_FILLEND
hint_event, // P32X_EVENT_HINT
};
// schedule event at some time 'after', in m68k clocks
@ -320,8 +367,12 @@ void p32x_event_schedule_sh2(SH2 *sh2, enum p32x_event event, int after)
p32x_event_schedule(now, event, after);
left_to_next = (event_time_next - now) * 3;
sh2_end_run(sh2, left_to_next);
left_to_next = C_M68K_TO_SH2(sh2, (int)(event_time_next - now));
if (sh2_cycles_left(sh2) > left_to_next) {
if (left_to_next < 1)
left_to_next = 0;
sh2_end_run(sh2, left_to_next);
}
}
static void p32x_run_events(unsigned int until)
@ -363,19 +414,19 @@ static void p32x_run_events(unsigned int until)
oldest, event_time_next);
}
static inline void run_sh2(SH2 *sh2, int m68k_cycles)
static void run_sh2(SH2 *sh2, unsigned int m68k_cycles)
{
int cycles, done;
unsigned int cycles, done;
pevt_log_sh2_o(sh2, EVT_RUN_START);
sh2->state |= SH2_STATE_RUN;
cycles = C_M68K_TO_SH2(*sh2, m68k_cycles);
cycles = C_M68K_TO_SH2(sh2, m68k_cycles);
elprintf_sh2(sh2, EL_32X, "+run %u %d @%08x",
sh2->m68krcycles_done, cycles, sh2->pc);
done = sh2_execute(sh2, cycles, PicoOpt & POPT_EN_DRC);
done = sh2_execute(sh2, cycles);
sh2->m68krcycles_done += C_SH2_TO_M68K(*sh2, done);
sh2->m68krcycles_done += C_SH2_TO_M68K(sh2, done);
sh2->state &= ~SH2_STATE_RUN;
pevt_log_sh2_o(sh2, EVT_RUN_END);
elprintf_sh2(sh2, EL_32X, "-run %u %d",
@ -409,28 +460,30 @@ void p32x_sync_other_sh2(SH2 *sh2, unsigned int m68k_target)
// there might be new event to schedule current sh2 to
if (event_time_next) {
left_to_event = event_time_next - m68k_target;
left_to_event *= 3;
left_to_event = C_M68K_TO_SH2(sh2, (int)(event_time_next - m68k_target));
if (sh2_cycles_left(sh2) > left_to_event) {
if (left_to_event < 1)
left_to_event = 1;
left_to_event = 0;
sh2_end_run(sh2, left_to_event);
}
}
}
#define STEP_LS 24
#define STEP_N 528 // at least one line (488)
#define sync_sh2s_normal p32x_sync_sh2s
//#define sync_sh2s_lockstep p32x_sync_sh2s
/* most timing is in 68k clock */
void sync_sh2s_normal(unsigned int m68k_target)
{
unsigned int now, target, timer_cycles;
unsigned int now, target, next, timer_cycles;
int cycles;
elprintf(EL_32X, "sh2 sync to %u", m68k_target);
if (!(Pico32x.regs[0] & P32XS_nRES)) {
if ((Pico32x.regs[0] & (P32XS_nRES|P32XS_ADEN)) != (P32XS_nRES|P32XS_ADEN)) {
msh2.m68krcycles_done = ssh2.m68krcycles_done = m68k_target;
return; // rare
}
@ -440,6 +493,7 @@ void sync_sh2s_normal(unsigned int m68k_target)
now = ssh2.m68krcycles_done;
timer_cycles = now;
pprof_start(m68k);
while (CYCLES_GT(m68k_target, now))
{
if (event_time_next && CYCLES_GE(now, event_time_next))
@ -448,47 +502,68 @@ void sync_sh2s_normal(unsigned int m68k_target)
target = m68k_target;
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
while (CYCLES_GT(target, now))
{
elprintf(EL_32X, "sh2 exec to %u %d,%d/%d, flags %x", target,
target - msh2.m68krcycles_done, target - ssh2.m68krcycles_done,
next = target;
if (CYCLES_GT(target, now + STEP_N))
next = now + STEP_N;
elprintf(EL_32X, "sh2 exec to %u %d,%d/%d, flags %x", next,
next - msh2.m68krcycles_done, next - ssh2.m68krcycles_done,
m68k_target - now, Pico32x.emu_flags);
pprof_start(ssh2);
if (!(ssh2.state & SH2_IDLE_STATES)) {
cycles = target - ssh2.m68krcycles_done;
cycles = next - ssh2.m68krcycles_done;
if (cycles > 0) {
run_sh2(&ssh2, cycles);
run_sh2(&ssh2, cycles > 20U ? cycles : 20U);
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
if (CYCLES_GT(next, target))
next = target;
}
}
pprof_end(ssh2);
pprof_start(msh2);
if (!(msh2.state & SH2_IDLE_STATES)) {
cycles = target - msh2.m68krcycles_done;
cycles = next - msh2.m68krcycles_done;
if (cycles > 0) {
run_sh2(&msh2, cycles);
run_sh2(&msh2, cycles > 20U ? cycles : 20U);
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
if (CYCLES_GT(next, target))
next = target;
}
}
pprof_end(msh2);
now = target;
if (!(msh2.state & SH2_IDLE_STATES)) {
if (CYCLES_GT(now, msh2.m68krcycles_done))
now = next;
if (CYCLES_GT(now, msh2.m68krcycles_done)) {
if (!(msh2.state & SH2_IDLE_STATES))
now = msh2.m68krcycles_done;
}
if (!(ssh2.state & SH2_IDLE_STATES)) {
if (CYCLES_GT(now, ssh2.m68krcycles_done))
if (CYCLES_GT(now, ssh2.m68krcycles_done)) {
if (!(ssh2.state & SH2_IDLE_STATES))
now = ssh2.m68krcycles_done;
}
if (CYCLES_GT(now, timer_cycles+STEP_N)) {
if (msh2.state & SH2_TIMER_RUN)
p32x_timer_do(&msh2, now - timer_cycles);
if (ssh2.state & SH2_TIMER_RUN)
p32x_timer_do(&ssh2, now - timer_cycles);
timer_cycles = now;
}
}
p32x_timers_do(now - timer_cycles);
if (msh2.state & SH2_TIMER_RUN)
p32x_timer_do(&msh2, now - timer_cycles);
if (ssh2.state & SH2_TIMER_RUN)
p32x_timer_do(&ssh2, now - timer_cycles);
timer_cycles = now;
}
pprof_end_sub(m68k);
// advance idle CPUs
if (msh2.state & SH2_IDLE_STATES) {
@ -499,32 +574,33 @@ void sync_sh2s_normal(unsigned int m68k_target)
if (CYCLES_GT(m68k_target, ssh2.m68krcycles_done))
ssh2.m68krcycles_done = m68k_target;
}
}
#define STEP_68K 24
// everyone is in sync now
Pico32x.comm_dirty = 0;
}
void sync_sh2s_lockstep(unsigned int m68k_target)
{
unsigned int mcycles;
mcycles = msh2.m68krcycles_done;
if (ssh2.m68krcycles_done < mcycles)
if (CYCLES_GT(mcycles, ssh2.m68krcycles_done))
mcycles = ssh2.m68krcycles_done;
while (mcycles < m68k_target) {
mcycles += STEP_68K;
while (CYCLES_GT(m68k_target, mcycles)) {
mcycles += STEP_LS;
sync_sh2s_normal(mcycles);
}
}
#define CPUS_RUN(m68k_cycles) do { \
if (PicoAHW & PAHW_MCD) \
if (PicoIn.AHW & PAHW_MCD) \
pcd_run_cpus(m68k_cycles); \
else \
SekRunM68k(m68k_cycles); \
\
if ((Pico32x.emu_flags & P32XF_Z80_32X_IO) && Pico.m.z80Run \
&& !Pico.m.z80_reset && (PicoOpt & POPT_EN_Z80)) \
&& !Pico.m.z80_reset && (PicoIn.opt & POPT_EN_Z80)) \
PicoSyncZ80(SekCyclesDone()); \
if (Pico32x.emu_flags & (P32XF_68KCPOLL|P32XF_68KVPOLL)) \
p32x_sync_sh2s(SekCyclesDone()); \
@ -536,23 +612,13 @@ void sync_sh2s_lockstep(unsigned int m68k_target)
void PicoFrame32x(void)
{
Pico.m.scanline = 0;
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_VBLK; // get out of vblank
if ((Pico32x.vdp_regs[0] & P32XV_Mx) != 0) // no forced blanking
Pico32x.vdp_regs[0x0a/2] &= ~P32XV_PEN; // no palette access
if (!(Pico32x.sh2_regs[0] & 0x80))
p32x_schedule_hint(NULL, SekCyclesDone());
p32x_sh2_poll_event(&msh2, SH2_STATE_VPOLL, 0);
p32x_sh2_poll_event(&ssh2, SH2_STATE_VPOLL, 0);
if (PicoAHW & PAHW_MCD)
if (PicoIn.AHW & PAHW_MCD)
pcd_prepare_frame();
PicoFrameStart();
if (Pico32xDrawMode != PDM32X_BOTH)
Pico.est.rendstatus |= PDRAW_SYNC_NEEDED;
PicoFrameHints();
sh2_drc_frame();
elprintf(EL_32X, "poll: %02x %02x %02x",
Pico32x.emu_flags & 3, msh2.state, ssh2.state);
@ -581,10 +647,24 @@ void Pico32xStateLoaded(int is_early)
return;
}
sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCyclesDone();
if (CYCLES_GE(sh2s[0].m68krcycles_done - Pico.t.m68c_aim, 500) ||
CYCLES_GE(sh2s[1].m68krcycles_done - Pico.t.m68c_aim, 500))
sh2s[0].m68krcycles_done = sh2s[1].m68krcycles_done = SekCyclesDone();
p32x_update_irls(NULL, SekCyclesDone());
p32x_timers_recalc();
p32x_pwm_state_loaded();
p32x_run_events(SekCyclesDone());
}
void Pico32xPrepare(void)
{
if (msh2.mult_m68k_to_sh2 == 0 || msh2.mult_sh2_to_m68k == 0)
Pico32xSetClocks(PICO_MSH2_HZ, 0);
if (ssh2.mult_m68k_to_sh2 == 0 || ssh2.mult_sh2_to_m68k == 0)
Pico32xSetClocks(0, PICO_MSH2_HZ);
sh2_execute_prepare(&msh2, PicoIn.opt & POPT_EN_DRC);
sh2_execute_prepare(&ssh2, PicoIn.opt & POPT_EN_DRC);
}
// vim:shiftwidth=2:ts=2:expandtab

View file

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

515
pico/32x/draw_arm.S Normal file
View file

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

View file

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

File diff suppressed because it is too large Load diff

288
pico/32x/memory_arm.S Normal file
View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

@ -1,5 +1,6 @@
/* svp */
#include "../pico_types.h"
#include "svp/ssp16.h"
typedef struct {
@ -14,15 +15,24 @@ void PicoSVPInit(void);
void PicoSVPStartup(void);
void PicoSVPMemSetup(void);
/* misc */
/* standard/ssf2 mapper */
extern int carthw_ssf2_active;
extern unsigned char carthw_ssf2_banks[8];
void carthw_ssf2_startup(void);
void carthw_ssf2_write8(u32 a, u32 d);
/* misc */
void carthw_Xin1_startup(void);
void carthw_realtec_startup(void);
void carthw_radica_startup(void);
void carthw_pier_startup(void);
void carthw_sf001_startup(void);
void carthw_sf002_startup(void);
void carthw_sf004_startup(void);
void carthw_sprot_startup(void);
void carthw_sprot_new_location(unsigned int a,
unsigned int mask, unsigned short val, int is_ro);
void carthw_prot_lk3_startup(void);
void carthw_lk3_startup(void);
void carthw_smw64_startup(void);

360
pico/carthw/eeprom_spi.c Normal file
View file

@ -0,0 +1,360 @@
/****************************************************************************
* Genesis Plus
* SPI Serial EEPROM (25xxx/95xxx) support
*
* Copyright (C) 2012 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#include "../pico_int.h"
#include "../cd/genplus_macros.h"
#include "eeprom_spi.h"
/* max supported size 64KB (25x512/95x512) */
#define SIZE_MASK 0xffff
#define PAGE_MASK 0x7f
/* hard-coded board implementation (!WP pin not used) */
#define BIT_DATA (0)
#define BIT_CLK (1)
#define BIT_HOLD (2)
#define BIT_CS (3)
typedef enum
{
STANDBY,
GET_OPCODE,
GET_ADDRESS,
WRITE_BYTE,
READ_BYTE
} T_STATE_SPI;
typedef struct
{
uint8 cs; /* !CS line state */
uint8 clk; /* SCLK line state */
uint8 out; /* SO line state */
uint8 status; /* status register */
uint8 opcode; /* 8-bit opcode */
uint8 buffer; /* 8-bit data buffer */
uint16 addr; /* 16-bit address */
uint32 cycles; /* current operation cycle */
T_STATE_SPI state; /* current operation state */
} T_EEPROM_SPI;
static T_EEPROM_SPI spi_eeprom;
void *eeprom_spi_init(int *size)
{
/* reset eeprom state */
memset(&spi_eeprom, 0, sizeof(T_EEPROM_SPI));
spi_eeprom.out = 1;
spi_eeprom.state = GET_OPCODE;
if (size)
*size = sizeof(T_EEPROM_SPI);
return &spi_eeprom;
}
void eeprom_spi_write(unsigned char data)
{
/* Make sure !HOLD is high */
if (data & (1 << BIT_HOLD))
{
/* Check !CS state */
if (data & (1 << BIT_CS))
{
/* !CS high -> end of current operation */
spi_eeprom.cycles = 0;
spi_eeprom.out = 1;
spi_eeprom.opcode = 0;
spi_eeprom.state = GET_OPCODE;
}
else
{
/* !CS low -> process current operation */
switch (spi_eeprom.state)
{
case GET_OPCODE:
{
/* latch data on CLK positive edge */
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
{
/* 8-bit opcode buffer */
spi_eeprom.opcode |= ((data >> BIT_DATA) & 1);
spi_eeprom.cycles++;
/* last bit ? */
if (spi_eeprom.cycles == 8)
{
/* reset cycles count */
spi_eeprom.cycles = 0;
/* Decode instruction */
switch (spi_eeprom.opcode)
{
case 0x01:
{
/* WRITE STATUS */
spi_eeprom.buffer = 0;
spi_eeprom.state = WRITE_BYTE;
break;
}
case 0x02:
{
/* WRITE BYTE */
spi_eeprom.addr = 0;
spi_eeprom.state = GET_ADDRESS;
break;
}
case 0x03:
{
/* READ BYTE */
spi_eeprom.addr = 0;
spi_eeprom.state = GET_ADDRESS;
break;
}
case 0x04:
{
/* WRITE DISABLE */
spi_eeprom.status &= ~0x02;
spi_eeprom.state = STANDBY;
break;
}
case 0x05:
{
/* READ STATUS */
spi_eeprom.buffer = spi_eeprom.status;
spi_eeprom.state = READ_BYTE;
break;
}
case 0x06:
{
/* WRITE ENABLE */
spi_eeprom.status |= 0x02;
spi_eeprom.state = STANDBY;
break;
}
default:
{
/* specific instructions (not supported) */
spi_eeprom.state = STANDBY;
break;
}
}
}
else
{
/* shift opcode value */
spi_eeprom.opcode = spi_eeprom.opcode << 1;
}
}
break;
}
case GET_ADDRESS:
{
/* latch data on CLK positive edge */
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
{
/* 16-bit address */
spi_eeprom.addr |= ((data >> BIT_DATA) & 1);
spi_eeprom.cycles++;
/* last bit ? */
if (spi_eeprom.cycles == 16)
{
/* reset cycles count */
spi_eeprom.cycles = 0;
/* mask unused address bits */
spi_eeprom.addr &= SIZE_MASK;
/* operation type */
if (spi_eeprom.opcode & 0x01)
{
/* READ operation */
spi_eeprom.buffer = Pico.sv.data[spi_eeprom.addr];
spi_eeprom.state = READ_BYTE;
}
else
{
/* WRITE operation */
spi_eeprom.buffer = 0;
spi_eeprom.state = WRITE_BYTE;
}
}
else
{
/* shift address value */
spi_eeprom.addr = spi_eeprom.addr << 1;
}
}
break;
}
case WRITE_BYTE:
{
/* latch data on CLK positive edge */
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
{
/* 8-bit data buffer */
spi_eeprom.buffer |= ((data >> BIT_DATA) & 1);
spi_eeprom.cycles++;
/* last bit ? */
if (spi_eeprom.cycles == 8)
{
/* reset cycles count */
spi_eeprom.cycles = 0;
/* write data to destination */
if (spi_eeprom.opcode & 0x01)
{
/* update status register */
spi_eeprom.status = (spi_eeprom.status & 0x02) | (spi_eeprom.buffer & 0x0c);
/* wait for operation end */
spi_eeprom.state = STANDBY;
}
else
{
/* Memory Array (write-protected) */
if (spi_eeprom.status & 2)
{
/* check array protection bits (BP0, BP1) */
switch ((spi_eeprom.status >> 2) & 0x03)
{
case 0x01:
{
/* $C000-$FFFF (sector #3) is protected */
if (spi_eeprom.addr < 0xC000)
{
Pico.sv.data[spi_eeprom.addr] = spi_eeprom.buffer;
}
break;
}
case 0x02:
{
/* $8000-$FFFF (sectors #2 and #3) is protected */
if (spi_eeprom.addr < 0x8000)
{
Pico.sv.data[spi_eeprom.addr] = spi_eeprom.buffer;
}
break;
}
case 0x03:
{
/* $0000-$FFFF (all sectors) is protected */
break;
}
default:
{
/* no sectors protected */
Pico.sv.data[spi_eeprom.addr] = spi_eeprom.buffer;
break;
}
}
}
/* reset data buffer */
spi_eeprom.buffer = 0;
/* increase array address (sequential writes are limited within the same page) */
spi_eeprom.addr = (spi_eeprom.addr & ~PAGE_MASK) | ((spi_eeprom.addr + 1) & PAGE_MASK);
}
}
else
{
/* shift data buffer value */
spi_eeprom.buffer = spi_eeprom.buffer << 1;
}
}
break;
}
case READ_BYTE:
{
/* output data on CLK positive edge */
if ((data & (1 << BIT_CLK)) && !spi_eeprom.clk)
{
/* read out bits */
spi_eeprom.out = (spi_eeprom.buffer >> (7 - spi_eeprom.cycles)) & 1;
spi_eeprom.cycles++;
/* last bit ? */
if (spi_eeprom.cycles == 8)
{
/* reset cycles count */
spi_eeprom.cycles = 0;
/* read from memory array ? */
if (spi_eeprom.opcode == 0x03)
{
/* read next array byte */
spi_eeprom.addr = (spi_eeprom.addr + 1) & SIZE_MASK;
spi_eeprom.buffer = Pico.sv.data[spi_eeprom.addr];
}
}
}
break;
}
default:
{
/* wait for !CS low->high transition */
break;
}
}
}
}
/* update input lines */
spi_eeprom.cs = (data >> BIT_CS) & 1;
spi_eeprom.clk = (data >> BIT_CLK) & 1;
}
unsigned int eeprom_spi_read(unsigned int address)
{
return (spi_eeprom.out << BIT_DATA);
}

47
pico/carthw/eeprom_spi.h Normal file
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,11 @@
#include "../pico_int.h"
#include "genplus_macros.h"
#include "cdd.h"
#include "cue.h"
#include "cd_parse.h"
#if defined(__GNUC__) && __GNUC__ >= 7
#pragma GCC diagnostic ignored "-Wformat-truncation"
#endif
static int handle_mp3(const char *fname, int index)
{
@ -45,6 +49,7 @@ static int handle_mp3(const char *fname, int index)
return -1;
}
track->type = CT_AUDIO;
track->fd = tmp_file;
track->offset = 0;
@ -61,6 +66,7 @@ static void to_upper(char *d, const char *s)
else
*d = *s;
}
*d = 0;
}
// cdd.c uses lba - 150
@ -81,7 +87,7 @@ int load_cd_image(const char *cd_img_name, int *type)
int iso_name_len, missed, cd_img_sectors;
char tmp_name[256], tmp_ext[10], tmp_ext_u[10];
track_t *tracks = cdd.toc.tracks;
cue_data_t *cue_data = NULL;
cd_data_t *cue_data = NULL;
pm_file *pmf;
if (PicoCDLoadProgressCB != NULL)
@ -94,20 +100,26 @@ int load_cd_image(const char *cd_img_name, int *type)
if (cue_data != NULL) {
cd_img_name = cue_data->tracks[1].fname;
*type = cue_data->tracks[1].type;
} else {
cue_data = chd_parse(cd_img_name);
if (cue_data != NULL)
*type = cue_data->tracks[1].type;
}
pmf = pm_open(cd_img_name);
if (pmf == NULL)
{
if (cue_data != NULL)
cue_destroy(cue_data);
cdparse_destroy(cue_data);
return -1;
}
tracks[0].fd = pmf;
tracks[0].fname = strdup(cd_img_name);
tracks[0].type = *type & CT_AUDIO;
if (*type == CT_ISO)
cd_img_sectors = pmf->size >>= 11; // size in sectors
else cd_img_sectors = pmf->size /= 2352;
cd_img_sectors = pmf->size >> 11; // size in sectors
else cd_img_sectors = pmf->size / 2352;
// cdd.c operates with lba - 150
tracks[0].start = 0;
@ -115,14 +127,14 @@ int load_cd_image(const char *cd_img_name, int *type)
tracks[0].offset = 0;
sprintf_lba(tmp_ext, sizeof(tmp_ext), 0);
elprintf(EL_STATUS, "Track 1: %s %9i DATA %s",
tmp_ext, tracks[0].end, cd_img_name);
elprintf(EL_STATUS, "Track 1: %s %9i %s %s",
tmp_ext, tracks[0].end, tracks[0].type ? "AUDIO" : "DATA ", cd_img_name);
lba = cd_img_sectors;
if (cue_data != NULL)
{
if (cue_data->tracks[2].fname == NULL) {
if (cue_data->track_count > 1 && cue_data->tracks[2].fname == NULL) {
// NULL fname means track2 is in same file as track1
lba = tracks[0].end = cue_data->tracks[2].sector_offset;
}
@ -148,6 +160,7 @@ int load_cd_image(const char *cd_img_name, int *type)
{
// assume raw, ignore header for wav..
tracks[index].fd = f;
tracks[index].fname = strdup(cue_data->tracks[n].fname);
tracks[index].offset = cue_data->tracks[n].sector_offset;
length = f->size / 2352;
}
@ -174,14 +187,16 @@ int load_cd_image(const char *cd_img_name, int *type)
length = cue_data->tracks[n].sector_xlength;
Pico_mcd->cdda_type = cue_data->tracks[n].type;
tracks[index].type = cue_data->tracks[n].type & CT_AUDIO;
tracks[index].start = lba;
lba += length;
tracks[index].end = lba;
sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO %s",
n, tmp_ext, length, cue_data->tracks[n].fname);
elprintf(EL_STATUS, "Track %2i: %s %9i %s %s", n, tmp_ext, length,
tracks[index].type ? "AUDIO" : "DATA ",
cue_data->tracks[n].fname ? cue_data->tracks[n].fname : "");
}
goto finish;
}
@ -235,6 +250,7 @@ int load_cd_image(const char *cd_img_name, int *type)
tracks[index].end = lba;
Pico_mcd->cdda_type = CT_MP3;
tracks[index].type = CT_AUDIO;
sprintf_lba(tmp_ext, sizeof(tmp_ext), tracks[index].start);
elprintf(EL_STATUS, "Track %2i: %s %9i AUDIO - %s",
@ -252,6 +268,7 @@ int load_cd_image(const char *cd_img_name, int *type)
finish:
cdd.toc.last = n - 1;
cdd.toc.end = lba;
tracks[n].start = cdd.toc.end;
sprintf_lba(tmp_ext, sizeof(tmp_ext), cdd.toc.end);
elprintf(EL_STATUS, "End CD - %s\n", tmp_ext);
@ -260,7 +277,7 @@ finish:
PicoCDLoadProgressCB(cd_img_name, 100);
if (cue_data != NULL)
cue_destroy(cue_data);
cdparse_destroy(cue_data);
return 0;
}

View file

@ -1,6 +1,7 @@
/*
* cuefile handling
* (C) notaz, 2008
* (C) irixxxx, 2020-2023
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
@ -8,11 +9,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cue.h"
#include "../pico_int.h"
#include "cd_parse.h"
// #define elprintf(w,f,...) printf(f "\n",##__VA_ARGS__);
#if defined(USE_LIBCHDR)
#include "libchdr/chd.h"
#include "libchdr/cdrom.h"
#endif
#ifdef _MSC_VER
#define snprintf _snprintf
#endif
@ -65,20 +71,23 @@ static int get_token(const char *buff, char *dest, int len)
static int get_ext(const char *fname, char ext[4],
char *base, size_t base_size)
{
int len, pos = 0;
size_t pos = 0;
char *p;
len = strlen(fname);
if (len >= 3)
pos = len - 3;
ext[0] = 0;
if (!(p = strrchr(fname, '.')))
return -1;
pos = p - fname;
strcpy(ext, fname + pos);
strncpy(ext, fname + pos + 1, 4/*sizeof(ext)*/-1);
ext[4/*sizeof(ext)*/-1] = '\0';
if (base != NULL) {
len = pos;
if (len + 1 < base_size)
len = base_size - 1;
memcpy(base, fname, len);
base[len] = 0;
if (base != NULL && base_size > 0) {
if (pos >= base_size)
pos = base_size - 1;
memcpy(base, fname, pos);
base[pos] = 0;
}
return pos;
}
@ -105,30 +114,122 @@ static int file_openable(const char *fname)
#define BEGINS(buff,str) (strncmp(buff,str,sizeof(str)-1) == 0)
/* note: tracks[0] is not used */
cue_data_t *cue_parse(const char *fname)
cd_data_t *chd_parse(const char *fname)
{
cd_data_t *data = NULL;
#if defined(USE_LIBCHDR)
cd_data_t *tmp;
int count = 0, count_alloc = 2;
int sectors = 0;
char metadata[256];
chd_file *cf = NULL;
if (fname == NULL || *fname == '\0')
return NULL;
if (chd_open(fname, CHD_OPEN_READ, NULL, &cf) != CHDERR_NONE)
goto out;
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (data == NULL)
goto out;
// get track info
while (count < CD_MAX_TRACKS) {
int track = 0, frames = 0, pregap = 0, postgap = 0;
char type[16], subtype[16], pgtype[16], pgsub[16];
type[0] = subtype[0] = pgtype[0] = pgsub[0] = 0;
// get metadata for track
if (chd_get_metadata(cf, CDROM_TRACK_METADATA2_TAG, count,
metadata, sizeof(metadata), 0, 0, 0) == CHDERR_NONE) {
if (sscanf(metadata, CDROM_TRACK_METADATA2_FORMAT,
&track, &type[0], &subtype[0], &frames,
&pregap, &pgtype[0], &pgsub[0], &postgap) != 8)
break;
}
else if (chd_get_metadata(cf, CDROM_TRACK_METADATA_TAG, count,
metadata, sizeof(metadata), 0, 0, 0) == CHDERR_NONE) {
if (sscanf(metadata, CDROM_TRACK_METADATA_FORMAT,
&track, &type[0], &subtype[0], &frames) != 4)
break;
}
else break; // all tracks completed
// metadata sanity check
if (track != count + 1 || frames < 0 || pregap < 0)
break;
// allocate track structure
count ++;
if (count >= count_alloc) {
count_alloc *= 2;
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (tmp == NULL) {
count--;
break;
}
data = tmp;
}
memset(&data->tracks[count], 0, sizeof(data->tracks[0]));
if (count == 1)
data->tracks[count].fname = strdup(fname);
if (!strcmp(type, "MODE1_RAW") || !strcmp(type, "MODE2_RAW")) {
data->tracks[count].type = CT_BIN;
} else if (!strcmp(type, "MODE1") || !strcmp(type, "MODE2_FORM1")) {
data->tracks[count].type = CT_ISO;
} else if (!strcmp(type, "AUDIO")) {
data->tracks[count].type = CT_CHD;
} else
break;
data->tracks[count].pregap = pregap;
if (pgtype[0] != 'V') // VAUDIO includes pregap in file
pregap = 0;
data->tracks[count].sector_offset = sectors + pregap;
data->tracks[count].sector_xlength = frames - pregap;
sectors += (((frames + CD_TRACK_PADDING - 1) / CD_TRACK_PADDING) * CD_TRACK_PADDING);
}
// check if image id OK, i.e. there are tracks, and length <= 80 min
if (count && sectors < (80*60*75)) {
data->track_count = count;
} else {
free(data);
data = NULL;
}
out:
if (cf)
chd_close(cf);
#endif
return data;
}
cd_data_t *cue_parse(const char *fname)
{
char current_file[256], *current_filep, cue_base[256];
char buff[256], buff2[32], ext[4], *p;
int ret, count = 0, count_alloc = 2, pending_pregap = 0;
size_t current_filep_size, fname_len;
cue_data_t *data = NULL;
cd_data_t *data = NULL, *tmp;
FILE *f = NULL;
void *tmp;
if (fname == NULL || (fname_len = strlen(fname)) == 0)
return NULL;
ret = get_ext(fname, ext, cue_base, sizeof(cue_base));
ret = get_ext(fname, ext, cue_base, sizeof(cue_base) - 4);
if (strcasecmp(ext, "cue") == 0) {
f = fopen(fname, "r");
}
else {
else if (strcasecmp(ext, "chd") != 0) {
// not a .cue, try one with the same base name
if (ret + 3 < sizeof(cue_base)) {
strcpy(cue_base + ret, "cue");
if (0 < ret && ret < sizeof(cue_base)) {
strcpy(cue_base + ret, ".cue");
f = fopen(cue_base, "r");
if (f == NULL) {
strcpy(cue_base + ret, "CUE");
strcpy(cue_base + ret, ".CUE");
f = fopen(cue_base, "r");
}
}
@ -147,18 +248,16 @@ cue_data_t *cue_parse(const char *fname)
// the basename of cuefile, no path
snprintf(cue_base, sizeof(cue_base), "%s", current_filep);
p = cue_base + strlen(cue_base);
if (p - 3 >= cue_base)
p[-3] = 0;
p = strrchr(cue_base, '.');
if (p) p[1] = '\0';
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cue_track));
data = calloc(1, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (data == NULL)
goto out;
while (!feof(f))
{
tmp = fgets(buff, sizeof(buff), f);
if (tmp == NULL)
if (fgets(buff, sizeof(buff), f) == NULL)
break;
mystrip(buff);
@ -175,7 +274,7 @@ cue_data_t *cue_parse(const char *fname)
count++;
if (count >= count_alloc) {
count_alloc *= 2;
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cue_track));
tmp = realloc(data, sizeof(*data) + count_alloc * sizeof(cd_track_t));
if (tmp == NULL) {
count--;
break;
@ -243,17 +342,22 @@ file_ok:
else if (strcasecmp(ext, "wav") == 0)
data->tracks[count].type = CT_WAV;
else if (strcasecmp(ext, "bin") == 0)
data->tracks[count].type = CT_BIN;
data->tracks[count].type = CT_RAW;
else {
elprintf(EL_STATUS, "unhandled audio format: \"%s\"",
data->tracks[count].fname);
}
}
else
else if (data->tracks[count-1].type & CT_AUDIO)
{
// propagate previous
data->tracks[count].type = data->tracks[count-1].type;
}
else
{
// assume raw binary data
data->tracks[count].type = CT_RAW;
}
}
else {
elprintf(EL_STATUS, "unhandled track type: \"%s\"", buff2);
@ -339,7 +443,7 @@ out:
}
void cue_destroy(cue_data_t *data)
void cdparse_destroy(cd_data_t *data)
{
int c;
@ -355,7 +459,7 @@ void cue_destroy(cue_data_t *data)
#if 0
int main(int argc, char *argv[])
{
cue_data_t *data = cue_parse(argv[1]);
cd_data_t *data = cue_parse(argv[1]);
int c;
if (data == NULL) return 1;
@ -365,7 +469,7 @@ int main(int argc, char *argv[])
data->tracks[c].sector_offset / (75*60), data->tracks[c].sector_offset / 75 % 60,
data->tracks[c].sector_offset % 75, data->tracks[c].pregap, data->tracks[c].fname);
cue_destroy(data);
cdparse_destroy(data);
return 0;
}

5
pico/cd/cd_parse.h Normal file
View file

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

View file

@ -66,6 +66,7 @@
/* PicoDrive: doing DMA at once, not using callbacks */
//#define DMA_BYTES_PER_LINE 512
#define DMA_CYCLES_PER_BYTE 4 // or 6?
enum dma_type {
word_ram_0_dma_w = 1,
@ -244,65 +245,66 @@ int cdc_context_load_old(uint8 *state)
#undef old_load
}
static void do_dma(enum dma_type type, int words_in)
static void do_dma(enum dma_type type, int bytes_in)
{
int dma_addr = (Pico_mcd->s68k_regs[0x0a] << 8) | Pico_mcd->s68k_regs[0x0b];
int dma_addr = (Pico_mcd->s68k_regs[0x0a] << 8) | Pico_mcd->s68k_regs[0x0b];
int src_addr = cdc.dac & 0x3ffe;
int dst_addr = dma_addr;
int words = words_in;
int bytes = bytes_in;
int words = bytes_in >> 1;
int dst_limit = 0;
uint8 *dst;
int len;
elprintf(EL_CD, "dma %d %04x->%04x %x",
type, cdc.dac, dst_addr, words_in);
type, cdc.dac, dst_addr, bytes_in);
switch (type)
{
case pcm_ram_dma_w:
dst_addr = (dst_addr << 2) & 0xffc;
if (dst_addr + words * 2 > 0x1000) {
if (dst_addr + bytes > 0x1000) {
elprintf(EL_ANOMALY, "pcm dma oflow: %x %x", dst_addr, words);
words = (0x1000 - dst_addr) / 2;
bytes = 0x1000 - dst_addr;
}
dst = Pico_mcd->pcm_ram_b[Pico_mcd->pcm.bank];
dst = dst + dst_addr;
while (words > 0)
while (bytes > 0)
{
if (src_addr + words * 2 > 0x4000) {
if (src_addr + bytes > 0x4000) {
len = 0x4000 - src_addr;
memcpy(dst, cdc.ram + src_addr, len);
dst += len;
src_addr = 0;
words -= len / 2;
bytes -= len;
continue;
}
memcpy(dst, cdc.ram + src_addr, words * 2);
memcpy(dst, cdc.ram + src_addr, bytes);
break;
}
goto update_dma;
case prg_ram_dma_w:
dst_addr <<= 3;
dst = Pico_mcd->prg_ram + dst_addr;
dst = Pico_mcd->prg_ram + dst_addr;
dst_limit = 0x80000;
break;
case word_ram_0_dma_w:
dst_addr = (dst_addr << 3) & 0x1fffe;
dst = Pico_mcd->word_ram1M[0] + dst_addr;
dst = Pico_mcd->word_ram1M[0] + dst_addr;
dst_limit = 0x20000;
break;
case word_ram_1_dma_w:
dst_addr = (dst_addr << 3) & 0x1fffe;
dst = Pico_mcd->word_ram1M[1] + dst_addr;
dst = Pico_mcd->word_ram1M[1] + dst_addr;
dst_limit = 0x20000;
break;
case word_ram_2M_dma_w:
dst_addr = (dst_addr << 3) & 0x3fffe;
dst = Pico_mcd->word_ram2M + dst_addr;
dst = Pico_mcd->word_ram2M + dst_addr;
dst_limit = 0x40000;
break;
@ -329,13 +331,15 @@ static void do_dma(enum dma_type type, int words_in)
break;
}
bytes_in &= ~1; // Todo leftover byte?
update_dma:
/* update DMA addresses */
cdc.dac += words_in * 2;
cdc.dac += bytes_in;
if (type == pcm_ram_dma_w)
dma_addr += words_in >> 1;
dma_addr += bytes_in >> 2;
else
dma_addr += words_in >> 2;
dma_addr += bytes_in >> 3;
Pico_mcd->s68k_regs[0x0a] = dma_addr >> 8;
Pico_mcd->s68k_regs[0x0b] = dma_addr;
@ -348,32 +352,34 @@ void cdc_dma_update(void)
{
/* transfer remaining words using 16-bit DMA */
//cdc.dma_w((cdc.dbc + 1) >> 1);
do_dma(cdc.dma_w, (cdc.dbc + 1) >> 1);
do_dma(cdc.dma_w, cdc.dbc + 1);
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
cdc.dbc = 0xf000;
cdc.dbc = 0xffff;
/* clear !DTEN and !DTBSY */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
/* pending Data Transfer End interrupt */
cdc.ifstat &= ~BIT_DTEI;
/* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN)
{
/* level 5 interrupt enabled ? */
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc DTE irq 5");
SekInterruptS68k(5);
}
}
/* clear DSR bit & set EDT bit (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0x80;
if (cdc.ifstat & BIT_DTEI) {
/* pending Data Transfer End interrupt */
cdc.ifstat &= ~BIT_DTEI;
/* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN)
{
/* level 5 interrupt enabled ? */
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc DTE irq 5");
pcd_irq_s68k(5, 1);
}
}
}
/* disable DMA transfer */
cdc.dma_w = 0;
}
@ -400,6 +406,9 @@ int cdc_decoder_update(uint8 header[4])
/* set !VALST */
cdc.stat[3] = 0x00;
/* set CRCOK bit */
cdc.stat[0] = BIT_DECEN;
/* pending decoder interrupt */
cdc.ifstat &= ~BIT_DECI;
@ -411,7 +420,7 @@ int cdc_decoder_update(uint8 header[4])
{
/* update IRQ level */
elprintf(EL_INTS, "cdc DEC irq 5");
SekInterruptS68k(5);
pcd_irq_s68k(5, 1);
}
}
@ -456,8 +465,11 @@ void cdc_reg_w(unsigned char data)
#ifdef LOG_CDC
elprintf(EL_STATUS, "CDC register %X write 0x%04x", Pico_mcd->s68k_regs[0x04+1] & 0x0F, data);
#endif
switch (Pico_mcd->s68k_regs[0x04+1] & 0x0F)
switch (Pico_mcd->s68k_regs[0x04+1] & 0x1F)
{
case 0x00:
break;
case 0x01: /* IFCTRL */
{
/* pending interrupts ? */
@ -469,13 +481,13 @@ void cdc_reg_w(unsigned char data)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc pending irq 5");
SekInterruptS68k(5);
pcd_irq_s68k(5, 1);
}
}
else // if (scd.pending & (1 << 5))
{
/* clear pending level 5 interrupts */
SekInterruptClearS68k(5);
pcd_irq_s68k(5, 0);
}
/* abort any data transfer if data output is disabled */
@ -498,7 +510,7 @@ void cdc_reg_w(unsigned char data)
case 0x03: /* DBCH */
cdc.dbc &= 0x00ff;
cdc.dbc |= data << 8;
cdc.dbc |= (data & 0x0f) << 8;
Pico_mcd->s68k_regs[0x04+1] = 0x04;
break;
@ -594,7 +606,7 @@ void cdc_reg_w(unsigned char data)
}
if (cdc.dma_w)
pcd_event_schedule_s68k(PCD_EVENT_DMA, cdc.dbc / 2);
pcd_event_schedule_s68k(PCD_EVENT_DMA, cdc.dbc * DMA_CYCLES_PER_BYTE);
}
Pico_mcd->s68k_regs[0x04+1] = 0x07;
@ -614,7 +626,7 @@ void cdc_reg_w(unsigned char data)
if ((cdc.ifstat | BIT_DECI) || !(cdc.ifctrl & BIT_DECIEN))
{
/* clear pending level 5 interrupt */
SekInterruptClearS68k(5);
pcd_irq_s68k(5, 0);
}
#endif
Pico_mcd->s68k_regs[0x04+1] = 0x08;
@ -635,8 +647,9 @@ void cdc_reg_w(unsigned char data)
case 0x0a: /* CTRL0 */
{
/* set CRCOK bit only if decoding is enabled */
cdc.stat[0] = data & BIT_DECEN;
/* reset DECI if decoder turned off */
if (!(data & BIT_DECEN))
cdc.ifstat |= BIT_DECI;
/* update decoding mode */
if (data & BIT_AUTORQ)
@ -695,14 +708,18 @@ void cdc_reg_w(unsigned char data)
break;
default: /* by default, SBOUT is not used */
Pico_mcd->s68k_regs[0x04+1] = (Pico_mcd->s68k_regs[0x04+1] + 1) & 0x1f;
break;
}
}
unsigned char cdc_reg_r(void)
{
switch (Pico_mcd->s68k_regs[0x04+1] & 0x0F)
switch (Pico_mcd->s68k_regs[0x04+1] & 0x1F)
{
case 0x00:
return 0xff;
case 0x01: /* IFSTAT */
Pico_mcd->s68k_regs[0x04+1] = 0x02;
return cdc.ifstat;
@ -774,15 +791,16 @@ unsigned char cdc_reg_r(void)
if ((cdc.ifstat | BIT_DTEI) || !(cdc.ifctrl & BIT_DTEIEN))
{
/* clear pending level 5 interrupt */
SekInterruptClearS68k(5);
pcd_irq_s68k(5, 0);
}
#endif
Pico_mcd->s68k_regs[0x04+1] = 0x00;
Pico_mcd->s68k_regs[0x04+1] = 0x10;
return data;
}
default: /* by default, COMIN is always empty */
Pico_mcd->s68k_regs[0x04+1] = (Pico_mcd->s68k_regs[0x04+1] + 1) & 0x1f;
return 0xff;
}
}
@ -810,28 +828,34 @@ unsigned short cdc_host_r(void)
if ((int16)cdc.dbc <= 0)
{
/* reset data byte counter (DBCH bits 4-7 should be set to 1) */
cdc.dbc = 0xf000;
cdc.dbc = 0xffff;
/* clear !DTEN and !DTBSY */
cdc.ifstat |= (BIT_DTBSY | BIT_DTEN);
/* pending Data Transfer End interrupt */
cdc.ifstat &= ~BIT_DTEI;
/* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN)
{
/* level 5 interrupt enabled ? */
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc DTE irq 5");
SekInterruptS68k(5);
}
}
/* clear DSR bit & set EDT bit (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0x80;
} else if ((int16)cdc.dbc <= 2)
{
if (cdc.ifstat & BIT_DTEI) {
/* pending Data Transfer End interrupt */
cdc.ifstat &= ~BIT_DTEI;
/* Data Transfer End interrupt enabled ? */
if (cdc.ifctrl & BIT_DTEIEN)
{
/* level 5 interrupt enabled ? */
if (Pico_mcd->s68k_regs[0x32+1] & PCDS_IEN5)
{
/* update IRQ level */
elprintf(EL_INTS, "cdc DTE irq 5");
pcd_irq_s68k(5, 1);
}
}
}
/* set DSR and EDT bit (SCD register $04) */
Pico_mcd->s68k_regs[0x04+0] = (Pico_mcd->s68k_regs[0x04+0] & 0x07) | 0xc0;
}
return data;

View file

@ -38,7 +38,7 @@
#include "../pico_int.h"
#include "genplus_macros.h"
#include "cue.h"
#include "cd_parse.h"
#include "cdd.h"
#ifdef USE_LIBTREMOR
@ -49,6 +49,9 @@
cdd_t cdd;
#define is_audio(index) \
(cdd.toc.tracks[index].type & CT_AUDIO)
/* BCD conversion lookup tables */
static const uint8 lut_BCD_8[100] =
{
@ -122,12 +125,14 @@ static const uint32 toc_ffightj[29] =
14553, 9834, 10542, 1699, 1792, 1781, 3783, 3052
};
#if 0
/* supported WAVE file header (16-bit stereo samples @44.1kHz) */
static const unsigned char waveHeader[32] =
{
0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
0x44,0xac,0x00,0x00,0x10,0xb1,0x02,0x00,0x04,0x00,0x10,0x00,0x64,0x61,0x74,0x61
};
#endif
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
@ -157,7 +162,7 @@ void cdd_reset(void)
cdd.latency = 0;
/* reset track index */
cdd.index = 0;
cdd.index = -1;
/* reset logical block address */
cdd.lba = 0;
@ -177,7 +182,7 @@ static void cdd_change_track(int index, int lba)
{
int i, base, lba_offset, lb_len;
for (i = index; i > 0; i--)
for (i = index; i >= 0; i--)
if (cdd.toc.tracks[i].fd != NULL)
break;
@ -191,6 +196,70 @@ static void cdd_change_track(int index, int lba)
cdda_start_play(base, lba_offset, lb_len);
}
static off_t read_pos = -1;
void cdd_seek(int index, int lba)
{
int aindex = (index < 0 ? -index : index);
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if track index has changed */
if (index != cdd.index)
{
/* close previous track VORBIS file structure to save memory */
if (cdd.index >= 0 && cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
/* open current track VORBIS file */
if (cdd.toc.tracks[aindex].vf.seekable)
{
ov_open(cdd.toc.tracks[aindex].fd,&cdd.toc.tracks[aindex].vf,0,0);
}
}
#endif
#endif
/* update current track index and LBA */
cdd.index = aindex;
cdd.lba = lba;
/* stay within track limits when seeking files */
if (lba < cdd.toc.tracks[cdd.index].start)
{
lba = cdd.toc.tracks[cdd.index].start;
}
/* seek to current block */
if (!is_audio(cdd.index))
{
/* DATA track */
read_pos = lba * cdd.sectorSize;
pm_seek(cdd.toc.tracks[cdd.index].fd, read_pos, SEEK_SET);
}
#ifdef USE_LIBTREMOR
else if (cdd.toc.tracks[cdd.index].vf.seekable)
{
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
}
#endif
#if 0
else if (cdd.toc.tracks[cdd.index].fd)
{
/* PCM AUDIO track */
fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
}
#else
else
{
cdd_change_track(cdd.index, lba);
}
#endif
}
int cdd_context_save(uint8 *state)
{
int bufferptr = 0;
@ -208,19 +277,8 @@ int cdd_context_save(uint8 *state)
int cdd_context_load(uint8 *state)
{
int lba;
int bufferptr = 0;
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
#endif
#endif
load_param(&cdd.cycles, sizeof(cdd.cycles));
load_param(&cdd.latency, sizeof(cdd.latency));
load_param(&cdd.index, sizeof(cdd.index));
@ -229,45 +287,8 @@ int cdd_context_load(uint8 *state)
load_param(&cdd.volume, sizeof(cdd.volume));
load_param(&cdd.status, sizeof(cdd.status));
/* adjust current LBA within track limit */
lba = cdd.lba;
if (lba < cdd.toc.tracks[cdd.index].start)
{
lba = cdd.toc.tracks[cdd.index].start;
}
/* seek to current track position */
if (!cdd.index)
{
/* DATA track */
if (cdd.toc.tracks[0].fd)
{
pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
}
}
#ifdef USE_LIBTREMOR
else if (cdd.toc.tracks[cdd.index].vf.seekable)
{
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* VORBIS file need to be opened first */
ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
#endif
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
}
#endif
#if 0
else if (cdd.toc.tracks[cdd.index].fd)
{
/* PCM AUDIO track */
fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
}
#else
else
{
cdd_change_track(cdd.index, lba);
}
#endif
cdd_seek(-cdd.index, cdd.lba);
return bufferptr;
}
@ -275,6 +296,8 @@ int cdd_context_load(uint8 *state)
int cdd_context_load_old(uint8 *state)
{
memcpy(&cdd.lba, state + 8, sizeof(cdd.lba));
cdd_seek(-cdd.index, cdd.lba);
return 12 * 4;
}
@ -316,9 +339,10 @@ int cdd_load(const char *filename, int type)
cdd.sectorSize = 2048;
}
ret = (type == CT_BIN) ? 2352 : 2048;
ret = (type == CT_ISO ? 2048 : 2352);
if (ret != cdd.sectorSize)
elprintf(EL_STATUS|EL_ANOMALY, "cd: type detection mismatch");
pm_sectorsize(cdd.sectorSize, cdd.toc.tracks[0].fd);
/* read CD image header + security code */
pm_read(header + 0x10, 0x200, cdd.toc.tracks[0].fd);
@ -441,11 +465,17 @@ int cdd_unload(void)
{
int i;
/* stop audio streaming */
Pico_mcd->cdda_stream = NULL;
/* close CD tracks */
if (cdd.toc.tracks[0].fd)
{
pm_close(cdd.toc.tracks[0].fd);
cdd.toc.tracks[0].fd = NULL;
if (cdd.toc.tracks[0].fname)
free(cdd.toc.tracks[0].fname);
cdd.toc.tracks[0].fname = NULL;
}
for (i = 1; i < cdd.toc.last; i++)
@ -464,7 +494,11 @@ int cdd_unload(void)
if (Pico_mcd->cdda_type == CT_MP3)
fclose(cdd.toc.tracks[i].fd);
else
pm_close(cdd.toc.tracks[0].fd);
pm_close(cdd.toc.tracks[i].fd);
cdd.toc.tracks[i].fd = NULL;
if (cdd.toc.tracks[i].fname)
free(cdd.toc.tracks[i].fname);
cdd.toc.tracks[i].fname = NULL;
/* detect single file images */
if (cdd.toc.tracks[i+1].fd == cdd.toc.tracks[i].fd)
@ -494,17 +528,29 @@ int cdd_unload(void)
void cdd_read_data(uint8 *dst)
{
/* only read DATA track sectors */
if ((cdd.lba >= 0) && (cdd.lba < cdd.toc.tracks[0].end))
if (!is_audio(cdd.index) && (cdd.lba >= cdd.toc.tracks[cdd.index].start) &&
(cdd.lba < cdd.toc.tracks[cdd.index].end))
{
off_t pos;
/* BIN format ? */
if (cdd.sectorSize == 2352)
{
/* skip 16-byte header */
pm_seek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET);
pos = cdd.lba * 2352 + 16;
}
else
{
pos = cdd.lba * cdd.sectorSize;
}
if (pos != read_pos) {
pm_seek(cdd.toc.tracks[cdd.index].fd, pos, SEEK_SET);
read_pos = pos;
}
/* read sector data (Mode 1 = 2048 bytes) */
pm_read(dst, 2048, cdd.toc.tracks[0].fd);
read_pos += pm_read(dst, 2048, cdd.toc.tracks[cdd.index].fd);
}
}
@ -674,32 +720,25 @@ void cdd_update(void)
error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
#endif
/* seeking disc */
if (cdd.status == CD_SEEK)
/* drive latency */
if (cdd.latency > 0)
{
/* drive latency */
if (cdd.latency > 0)
{
cdd.latency--;
return;
}
/* drive is ready */
cdd.status = CD_READY;
cdd.latency--;
return;
}
/* reading disc */
else if (cdd.status == CD_PLAY)
if (cdd.status == CD_PLAY)
{
/* drive latency */
if (cdd.latency > 0)
if (cdd.index >= cdd.toc.last)
{
cdd.latency--;
/* end of disc */
cdd.status = CD_END;
return;
}
/* track type */
if (!cdd.index)
if (!is_audio(cdd.index))
{
/* DATA sector header (CD-ROM Mode 1) */
uint8 header[4];
@ -710,9 +749,9 @@ void cdd_update(void)
header[3] = 0x01;
/* data track sector read is controlled by CDC */
cdd.lba += cdc_decoder_update(header);
cdc_decoder_update(header);
}
else if (cdd.index < cdd.toc.last)
else
{
uint8 header[4] = { 0, };
@ -725,57 +764,19 @@ void cdd_update(void)
/* audio blocks are still sent to CDC as well as CD DAC/Fader */
cdc_decoder_update(header);
}
/* next audio block is automatically read */
cdd.lba++;
}
else
{
/* end of disc */
cdd.status = CD_END;
return;
}
/* next block is automatically read */
cdd.lba++;
/* check end of current track */
if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
{
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
#endif
#endif
/* play next track */
cdd.index++;
/* PAUSE between tracks */
Pico_mcd->s68k_regs[0x36+0] = 0x01;
/* seek to next audio track start */
#ifdef USE_LIBTREMOR
if (cdd.toc.tracks[cdd.index].vf.seekable)
{
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* VORBIS file need to be opened first */
ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
#endif
ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, -cdd.toc.tracks[cdd.index].offset);
}
else
#endif
#if 0
if (cdd.toc.tracks[cdd.index].fd)
{
fseek(cdd.toc.tracks[cdd.index].fd, (cdd.toc.tracks[cdd.index].start * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
}
#else
{
cdd_change_track(cdd.index, cdd.lba);
}
#endif
cdd_seek(cdd.index + 1, cdd.lba);
}
}
@ -788,100 +789,51 @@ void cdd_update(void)
/* check current track limits */
if (cdd.lba >= cdd.toc.tracks[cdd.index].end)
{
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
#endif
#endif
/* next track */
cdd.index++;
/* skip directly to track start position */
cdd.lba = cdd.toc.tracks[cdd.index].start;
/* AUDIO track playing ? */
if (cdd.status == CD_PLAY)
if (cdd.index >= cdd.toc.last)
{
Pico_mcd->s68k_regs[0x36+0] = 0x00;
/* no AUDIO track playing */
Pico_mcd->s68k_regs[0x36+0] = 0x01;
/* end of disc */
cdd.lba = cdd.toc.end;
cdd.status = CD_END;
}
else
{
cdd_seek(cdd.index + 1, cdd.toc.tracks[cdd.index+1].start);
/* AUDIO track playing ? */
if (cdd.status == CD_PLAY && is_audio(cdd.index))
{
Pico_mcd->s68k_regs[0x36+0] = 0x00;
}
}
}
else if (cdd.lba < cdd.toc.tracks[cdd.index].start)
{
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
#endif
#endif
/* previous track */
cdd.index--;
/* skip directly to track end position */
cdd.lba = cdd.toc.tracks[cdd.index].end;
}
/* check disc limits */
if (cdd.index < 0)
{
cdd.index = 0;
cdd.lba = 0;
}
else if (cdd.index >= cdd.toc.last)
{
/* no AUDIO track playing */
Pico_mcd->s68k_regs[0x36+0] = 0x01;
/* end of disc */
cdd.index = cdd.toc.last;
cdd.lba = cdd.toc.end;
cdd.status = CD_END;
return;
}
/* seek to current block */
if (!cdd.index)
{
/* no AUDIO track playing */
Pico_mcd->s68k_regs[0x36+0] = 0x01;
/* DATA track */
pm_seek(cdd.toc.tracks[0].fd, cdd.lba * cdd.sectorSize, SEEK_SET);
}
#ifdef USE_LIBTREMOR
else if (cdd.toc.tracks[cdd.index].vf.seekable)
{
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if a new track is being played */
if (!cdd.toc.tracks[cdd.index].vf.datasource)
if (cdd.index <= 0)
{
/* VORBIS file need to be opened first */
ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0);
cdd_seek(0, 0);
}
else
{
cdd_seek(cdd.index - 1, cdd.toc.tracks[cdd.index-1].end);
}
#endif
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (cdd.lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset);
}
#endif
#if 0
else if (cdd.toc.tracks[cdd.index].fd)
if (!is_audio(cdd.index))
{
/* PCM AUDIO track */
fseek(cdd.toc.tracks[cdd.index].fd, (cdd.lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET);
/* no AUDIO track playing */
Pico_mcd->s68k_regs[0x36+0] = 0x01;
}
#else
else
{
cdd_change_track(cdd.index, cdd.lba);
}
#endif
}
if (Pico_mcd->m.state_flags & PCD_ST_CDD_CMD) {
/* pending delayed command */
cdd_process();
Pico_mcd->m.state_flags &= ~PCD_ST_CDD_CMD;
}
}
@ -898,15 +850,25 @@ void cdd_process(void)
{
case 0x00: /* Drive Status */
{
/* RS1-RS8 normally unchanged */
Pico_mcd->s68k_regs[0x38+0] = cdd.status;
if (cdd.latency == 0) {
/* RS1-RS8 normally unchanged */
Pico_mcd->s68k_regs[0x38+0] = cdd.status;
/* unless RS1 indicated invalid track infos */
if (Pico_mcd->s68k_regs[0x38+1] == 0x0f)
{
/* and SEEK has ended */
if (cdd.status != CD_SEEK)
/* unless RS1 indicated invalid track infos */
if (Pico_mcd->s68k_regs[0x38+1] == 0x0f ||
Pico_mcd->s68k_regs[0x38+1] == 0x00 ||
Pico_mcd->s68k_regs[0x38+1] == 0x01)
{
int lba = cdd.lba + 150 - cdd.latency;
if (Pico_mcd->s68k_regs[0x38+1] == 0x01)
lba = abs(cdd.lba - cdd.toc.tracks[cdd.index].start);
if (Pico_mcd->s68k_regs[0x38+1] == 0x0f)
Pico_mcd->s68k_regs[0x38+1] = 0x00;
set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
set_reg16(0x3e, lut_BCD_16[(lba%75)]);
Pico_mcd->s68k_regs[0x40+0] = is_audio(cdd.index) ? 0x00 : 0x04;
} else if (Pico_mcd->s68k_regs[0x38+1] == 0x02) {
/* then return valid track infos, e.g current track number in RS2-RS3 (fixes Lunar - The Silver Star) */
Pico_mcd->s68k_regs[0x38+1] = 0x02;
set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[cdd.index + 1] : 0x0A0A);
@ -948,18 +910,19 @@ void cdd_process(void)
set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
set_reg16(0x3e, lut_BCD_16[(lba%75)]);
Pico_mcd->s68k_regs[0x40+0] = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
Pico_mcd->s68k_regs[0x40+0] = is_audio(cdd.index) ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
break;
}
case 0x01: /* Current Track Relative Time (MM:SS:FF) */
{
int lba = cdd.lba - cdd.toc.tracks[cdd.index].start;
if (lba < 0) lba = 0;
set_reg16(0x38, (cdd.status << 8) | 0x01);
set_reg16(0x3a, lut_BCD_16[(lba/75)/60]);
set_reg16(0x3c, lut_BCD_16[(lba/75)%60]);
set_reg16(0x3e, lut_BCD_16[(lba%75)]);
Pico_mcd->s68k_regs[0x40+0] = cdd.index ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
Pico_mcd->s68k_regs[0x40+0] = is_audio(cdd.index) ? 0x00 : 0x04; /* Current block flags in RS8 (bit0 = mute status, bit1: pre-emphasis status, bit2: track type) */
break;
}
@ -1011,6 +974,16 @@ void cdd_process(void)
break;
}
case 0x06: /* Latest Error Information */
{
set_reg16(0x38, (cdd.status << 8) | 0x06);
set_reg16(0x3a, 0x0000);
set_reg16(0x3c, 0x0000);
set_reg16(0x3e, 0x0000);
Pico_mcd->s68k_regs[0x40+0] = 0x00;
break;
}
default:
{
#ifdef LOG_ERROR
@ -1032,6 +1005,12 @@ void cdd_process(void)
(Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
(Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
/* if drive is currently reading, another block or 2 are decoded before the seek starts */
if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD;
return;
}
/* CD drive latency */
if (!cdd.latency)
{
@ -1040,7 +1019,7 @@ void cdd_process(void)
/* Wolf Team games (Anet Futatabi, Cobra Command, Road Avenger & Time Gal) need at least 6 interrupts delay */
/* Space Adventure Cobra (2nd morgue scene) needs at least 13 interrupts delay (incl. seek time, so 6 is OK) */
/* Jeopardy & ESPN Sunday Night NFL are picky about this as well: 10 interrupts delay (+ seek time) seems OK */
cdd.latency = 10;
cdd.latency = 11;
}
/* CD drive seek time */
@ -1057,66 +1036,14 @@ void cdd_process(void)
cdd.latency += (((cdd.lba - lba) * 120) / 270000);
}
/* update current LBA */
cdd.lba = lba;
/* block transfer always starts 3 blocks earlier */
lba -= 3;
/* get track index */
while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if track index has changed */
if (index != cdd.index)
{
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
/* open current track VORBIS file */
if (cdd.toc.tracks[index].vf.seekable)
{
ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
}
}
#endif
#endif
/* update current track index */
cdd.index = index;
/* stay within track limits when seeking files */
if (lba < cdd.toc.tracks[index].start)
{
lba = cdd.toc.tracks[index].start;
}
/* seek to current block */
if (!index)
{
/* DATA track */
pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
}
#ifdef USE_LIBTREMOR
else if (cdd.toc.tracks[index].vf.seekable)
{
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
}
#endif
#if 0
else if (cdd.toc.tracks[index].fd)
{
/* PCM AUDIO track */
fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
}
#else
else
{
cdd_change_track(index, lba);
}
#endif
/* seek to block */
cdd_seek(index, lba);
/* no audio track playing (yet) */
Pico_mcd->s68k_regs[0x36+0] = 0x01;
@ -1125,12 +1052,12 @@ void cdd_process(void)
cdd.status = CD_PLAY;
/* return track index in RS2-RS3 */
set_reg16(0x38, (CD_PLAY << 8) | 0x02);
set_reg16(0x3a, (cdd.index < cdd.toc.last) ? lut_BCD_16[index + 1] : 0x0A0A);
set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
set_reg16(0x3a, 0x0000);
set_reg16(0x3c, 0x0000);
set_reg16(0x3e, 0x0000);
Pico_mcd->s68k_regs[0x40+0] = 0x00;
break;
set_reg16(0x40, ~(CD_SEEK + 0xf) & 0x0f);
return;
}
case 0x04: /* Seek */
@ -1143,6 +1070,12 @@ void cdd_process(void)
(Pico_mcd->s68k_regs[0x46+0] * 10 + Pico_mcd->s68k_regs[0x46+1])) * 75 +
(Pico_mcd->s68k_regs[0x48+0] * 10 + Pico_mcd->s68k_regs[0x48+1]) - 150;
/* if drive is currently reading, another block or 2 are decoded before the seek starts */
if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD;
return;
}
/* CD drive seek time */
/* We are using similar linear model as above, although still not exactly accurate, */
/* it works fine for Switch/Panic! intro (Switch needs at least 30 interrupts while */
@ -1156,67 +1089,17 @@ void cdd_process(void)
cdd.latency = ((cdd.lba - lba) * 120) / 270000;
}
/* update current LBA */
cdd.lba = lba;
/* get current track index */
/* get track index */
while ((cdd.toc.tracks[index].end <= lba) && (index < cdd.toc.last)) index++;
#ifdef USE_LIBTREMOR
#ifdef DISABLE_MANY_OGG_OPEN_FILES
/* check if track index has changed */
if (index != cdd.index)
{
/* close previous track VORBIS file structure to save memory */
if (cdd.toc.tracks[cdd.index].vf.datasource)
{
ogg_free(cdd.index);
}
/* open current track VORBIS file */
if (cdd.toc.tracks[index].vf.seekable)
{
ov_open(cdd.toc.tracks[index].fd,&cdd.toc.tracks[index].vf,0,0);
}
}
#endif
#endif
/* update current track index */
cdd.index = index;
/* stay within track limits */
if (lba < cdd.toc.tracks[index].start)
{
lba = cdd.toc.tracks[index].start;
}
/* seek to current block */
if (!index)
{
/* DATA track */
pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET);
}
#ifdef USE_LIBTREMOR
else if (cdd.toc.tracks[index].vf.seekable)
{
/* VORBIS AUDIO track */
ov_pcm_seek(&cdd.toc.tracks[index].vf, (lba - cdd.toc.tracks[index].start) * 588 - cdd.toc.tracks[index].offset);
}
#endif
#if 0
else if (cdd.toc.tracks[index].fd)
{
/* PCM AUDIO track */
fseek(cdd.toc.tracks[index].fd, (lba * 2352) - cdd.toc.tracks[index].offset, SEEK_SET);
}
#endif
/* seek to block */
cdd_seek(index, lba);
/* no audio track playing */
Pico_mcd->s68k_regs[0x36+0] = 0x01;
/* update status */
cdd.status = CD_SEEK;
cdd.status = CD_READY;
/* unknown RS1-RS8 values (returning 0xF in RS1 invalidates track infos in RS2-RS8 and fixes Final Fight CD intro when seek time is emulated) */
set_reg16(0x38, (CD_SEEK << 8) | 0x0f);
@ -1229,6 +1112,12 @@ void cdd_process(void)
case 0x06: /* Pause */
{
/* if drive is currently reading, another block or 2 are decoded before the seek starts */
if (cdd.status == CD_PLAY && !(Pico_mcd->m.state_flags & PCD_ST_CDD_CMD)) {
Pico_mcd->m.state_flags |= PCD_ST_CDD_CMD;
return;
}
/* no audio track playing */
Pico_mcd->s68k_regs[0x36+0] = 0x01;
@ -1239,6 +1128,17 @@ void cdd_process(void)
case 0x07: /* Resume */
{
int lba = (cdd.lba < 0 ? 0 : cdd.lba);
/* CD drive latency */
if (!cdd.latency)
{
cdd.latency = 11;
}
/* always restart 4 blocks earlier */
cdd_seek(cdd.index, lba - 4);
/* update status (RS1-RS8 unchanged) */
cdd.status = Pico_mcd->s68k_regs[0x38+0] = CD_PLAY;
break;
@ -1295,8 +1195,8 @@ void cdd_process(void)
set_reg16(0x3e, 0x0000);
set_reg16(0x40, 0x000f);
if (PicoMCDcloseTray)
PicoMCDcloseTray();
if (PicoIn.mcdTrayClose)
PicoIn.mcdTrayClose();
return;
}
@ -1314,8 +1214,8 @@ void cdd_process(void)
set_reg16(0x3e, 0x0000);
set_reg16(0x40, ~CD_OPEN & 0x0f);
if (PicoMCDopenTray)
PicoMCDopenTray();
if (PicoIn.mcdTrayOpen)
PicoIn.mcdTrayOpen();
return;
}

View file

@ -60,6 +60,8 @@
/* CD track */
typedef struct
{
int type;
char *fname;
void *fd;
#ifdef USE_LIBTREMOR
OggVorbis_File vf;

View file

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

View file

@ -5,15 +5,15 @@
#undef int16
#undef int32
#define uint8 unsigned char
#define uint16 unsigned short
#define uint32 unsigned int
#define int8 signed char
#define int16 signed short
#define int32 signed int
#define uint8 u8
#define uint16 u16
#define uint32 u32
#define int8 s8
#define int16 s16
#define int32 s32
#define READ_BYTE(BASE, ADDR) (BASE)[(ADDR)^1]
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[(ADDR)^1] = (VAL)
#define READ_BYTE(BASE, ADDR) (BASE)[MEM_BE2(ADDR)]
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[MEM_BE2(ADDR)] = (VAL)
#define load_param(param, size) \
memcpy(param, &state[bufferptr], size); \

View file

@ -43,6 +43,7 @@ typedef struct
//uint32 cycles; /* current cycles count for graphics operation */
//uint32 cyclesPerLine; /* current graphics operation timings */
uint32 dotMask; /* stamp map size mask */
uint32 stampMask; /* stamp number mask */
uint16 *tracePtr; /* trace vector pointer */
uint16 *mapPtr; /* stamp map table base address */
uint8 stampShift; /* stamp pixel shift value (related to stamp size) */
@ -52,7 +53,8 @@ typedef struct
uint32 y_step; /* pico: render line step */
uint8 lut_prio[4][0x10][0x10]; /* WORD-RAM data writes priority lookup table */
uint8 lut_pixel[0x200]; /* Graphics operation dot offset lookup table */
uint8 lut_cell[0x100]; /* Graphics operation stamp offset lookup table */
uint16 lut_cell2[0x80]; /* Graphics operation stamp offset lookup table */
uint16 lut_cell4[0x80]; /* Graphics operation stamp offset lookup table */
} gfx_t;
static gfx_t gfx;
@ -66,7 +68,7 @@ static void gfx_schedule(void);
void gfx_init(void)
{
int i, j;
uint8 mask, row, col, temp;
uint8 row, col, temp;
memset(&gfx, 0, sizeof(gfx));
@ -87,24 +89,23 @@ void gfx_init(void)
}
/* Initialize cell lookup table */
/* table entry = yyxxshrr (8 bits) */
/* table entry = yyxxhrr (7 bits) */
/* with: yy = cell row (0-3) */
/* xx = cell column (0-3) */
/* s = stamp size (0=16x16, 1=32x32) */
/* hrr = HFLIP & ROTATION bits */
for (i=0; i<0x100; i++)
for (i=0; i<0x80; i++)
{
/* one stamp = 2x2 cells (16x16) or 4x4 cells (32x32) */
mask = (i & 8) ? 3 : 1;
row = (i >> 6) & mask;
col = (i >> 4) & mask;
row = (i >> 5) & 3;
col = (i >> 3) & 3;
if (i & 4) { col = col ^ mask; } /* HFLIP (always first) */
if (i & 2) { col = col ^ mask; row = row ^ mask; } /* ROLL1 */
if (i & 1) { temp = col; col = row ^ mask; row = temp; } /* ROLL0 */
if (i & 4) { col = col ^ 3; } /* HFLIP (always first) */
if (i & 2) { col = col ^ 3; row = row ^ 3; } /* ROLL1 */
if (i & 1) { temp = col; col = row ^ 3; row = temp; } /* ROLL0 */
/* cell offset (0-3 or 0-15) */
gfx.lut_cell[i] = row + col * (mask + 1);
gfx.lut_cell2[i] = ((row&1) + (col&1) * 2) << 6;
gfx.lut_cell4[i] = ((row&3) + (col&3) * 4) << 6;
}
/* Initialize pixel lookup table */
@ -175,12 +176,136 @@ int gfx_context_load(const uint8 *state)
return bufferptr;
}
static inline int gfx_pixel(uint32 xpos, uint32 ypos, uint16 *lut_cell)
{
uint16 stamp_data;
uint32 stamp_index;
uint8 pixel_out = 0x00;
/* check if pixel is outside stamp map */
if (((xpos | ypos) & ~gfx.dotMask) == 0)
{
/* read stamp map table data */
stamp_data = gfx.mapPtr[(xpos >> gfx.stampShift) | ((ypos >> gfx.stampShift) << gfx.mapShift)];
/* stamp generator base index */
/* sss ssssssss ccyyyxxx (16x16) or sss sssssscc ccyyyxxx (32x32) */
/* with: s = stamp number (1 stamp = 16x16 or 32x32 pixels) */
/* c = cell offset (0-3 for 16x16, 0-15 for 32x32) */
/* yyy = line offset (0-7) */
/* xxx = pixel offset (0-7) */
stamp_index = (stamp_data & gfx.stampMask) << 8;
if (stamp_index)
{
/* extract HFLIP & ROTATION bits */
stamp_data = (stamp_data >> 13) & 7;
/* cell offset (0-3 or 0-15) */
/* table entry = yyxxhrr (7 bits) */
/* with: yy = cell row (0-3) = (ypos >> (11 + 3)) & 3 */
/* xx = cell column (0-3) = (xpos >> (11 + 3)) & 3 */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= lut_cell[stamp_data | ((ypos >> 9) & 0x60) | ((xpos >> 11) & 0x18)];
/* pixel offset (0-63) */
/* table entry = yyyxxxhrr (9 bits) */
/* with: yyy = pixel row (0-7) = (ypos >> 11) & 7 */
/* xxx = pixel column (0-7) = (xpos >> 11) & 7 */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= gfx.lut_pixel[stamp_data | ((ypos >> 5) & 0x1c0) | ((xpos >> 8) & 0x38)];
/* read pixel pair (2 pixels/byte) */
pixel_out = READ_BYTE(Pico_mcd->word_ram2M, stamp_index >> 1);
/* extract left or right pixel */
pixel_out >>= 4 * !(stamp_index & 1);
pixel_out &= 0x0f;
}
}
return pixel_out;
}
#define RENDER_LOOP(N, UPDP, COND1, COND2) do { \
if (bufferIndex & 1) { \
bufferIndex ^= 1; \
goto right##N; /* no initial left pixel */ \
} \
/* process all dots */ \
while (width--) \
{ \
/* left pixel */ \
xpos &= mask; \
ypos &= mask; \
\
if (COND1) { \
pixel_out = gfx_pixel(xpos, ypos, lut_cell); \
UPDP; \
} \
\
if (COND2) { \
/* read out paired pixel data */ \
pixel_in = READ_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1); \
\
/* priority mode write */ \
pixel_in = (lut_prio[(pixel_in & 0xf0) >> 4][pixel_out] << 4) | \
(pixel_in & 0x0f); \
\
/* write data to image buffer */ \
WRITE_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1, pixel_in); \
} \
\
/* increment pixel position */ \
xpos += xoffset; \
ypos += yoffset; \
\
right##N: \
if (width-- == 0) break; \
\
/* right pixel */ \
xpos &= mask; \
ypos &= mask; \
\
if (COND1) { \
pixel_out = gfx_pixel(xpos, ypos, lut_cell); \
UPDP; \
} \
\
if (COND2) { \
/* read out paired pixel data */ \
pixel_in = READ_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1); \
\
/* priority mode write */ \
pixel_in = (lut_prio[pixel_in & 0x0f][pixel_out]) | \
(pixel_in & 0xf0); \
\
/* write data to image buffer */ \
WRITE_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1, pixel_in); \
} \
\
/* increment pixel position */ \
xpos += xoffset; \
ypos += yoffset; \
\
/* next pixel */ \
bufferIndex += 2; \
/* check current pixel position */ \
if ((bufferIndex & 7) == 0) \
{ \
/* next cell: increment buffer offset by one column (minus 8 pixels) */ \
bufferIndex += gfx.bufferOffset-1; \
} \
} \
} while (0)
static void gfx_render(uint32 bufferIndex, uint32 width)
{
uint8 pixel_in, pixel_out;
uint16 stamp_data;
uint32 stamp_index;
uint32 priority;
uint8 (*lut_prio)[0x10];
uint16 *lut_cell;
uint32 mask;
/* pixel map start position for current line (13.3 format converted to 13.11) */
uint32 xpos = *gfx.tracePtr++ << 8;
@ -192,126 +317,30 @@ static void gfx_render(uint32 bufferIndex, uint32 width)
priority = (Pico_mcd->s68k_regs[2] << 8) | Pico_mcd->s68k_regs[3];
priority = (priority >> 3) & 0x03;
lut_prio = gfx.lut_prio[priority];
/* process all dots */
while (width--)
lut_cell = (Pico_mcd->s68k_regs[0x58+1] & 0x02) ? gfx.lut_cell4 : gfx.lut_cell2;
/* check if stamp map is repeated */
mask = 0xffffff; /* 24-bit range */
if (Pico_mcd->s68k_regs[0x58+1] & 0x01)
{
/* check if stamp map is repeated */
if (Pico_mcd->s68k_regs[0x58+1] & 0x01)
{
/* stamp map range */
xpos &= gfx.dotMask;
ypos &= gfx.dotMask;
}
else
{
/* 24-bit range */
xpos &= 0xffffff;
ypos &= 0xffffff;
}
/* stamp map range */
mask = gfx.dotMask;
}
/* check if pixel is outside stamp map */
if ((xpos | ypos) & ~gfx.dotMask)
{
/* force pixel output to 0 */
pixel_out = 0x00;
}
else
{
/* read stamp map table data */
stamp_data = gfx.mapPtr[(xpos >> gfx.stampShift) | ((ypos >> gfx.stampShift) << gfx.mapShift)];
/* stamp generator base index */
/* sss ssssssss ccyyyxxx (16x16) or sss sssssscc ccyyyxxx (32x32) */
/* with: s = stamp number (1 stamp = 16x16 or 32x32 pixels) */
/* c = cell offset (0-3 for 16x16, 0-15 for 32x32) */
/* yyy = line offset (0-7) */
/* xxx = pixel offset (0-7) */
stamp_index = (stamp_data & 0x7ff) << 8;
if (stamp_index)
{
/* extract HFLIP & ROTATION bits */
stamp_data = (stamp_data >> 13) & 7;
/* cell offset (0-3 or 0-15) */
/* table entry = yyxxshrr (8 bits) */
/* with: yy = cell row (0-3) = (ypos >> (11 + 3)) & 3 */
/* xx = cell column (0-3) = (xpos >> (11 + 3)) & 3 */
/* s = stamp size (0=16x16, 1=32x32) */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= gfx.lut_cell[
stamp_data | ((Pico_mcd->s68k_regs[0x58+1] & 0x02) << 2 )
| ((ypos >> 8) & 0xc0) | ((xpos >> 10) & 0x30)] << 6;
/* pixel offset (0-63) */
/* table entry = yyyxxxhrr (9 bits) */
/* with: yyy = pixel row (0-7) = (ypos >> 11) & 7 */
/* xxx = pixel column (0-7) = (xpos >> 11) & 7 */
/* hrr = HFLIP & ROTATION bits */
stamp_index |= gfx.lut_pixel[stamp_data | ((xpos >> 8) & 0x38) | ((ypos >> 5) & 0x1c0)];
/* read pixel pair (2 pixels/byte) */
pixel_out = READ_BYTE(Pico_mcd->word_ram2M, stamp_index >> 1);
/* extract left or rigth pixel */
if (stamp_index & 1)
{
pixel_out &= 0x0f;
}
else
{
pixel_out >>= 4;
}
}
else
{
/* stamp 0 is not used: force pixel output to 0 */
pixel_out = 0x00;
}
}
/* read out paired pixel data */
pixel_in = READ_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1);
/* update left or rigth pixel */
if (bufferIndex & 1)
{
/* priority mode write */
pixel_out = gfx.lut_prio[priority][pixel_in & 0x0f][pixel_out];
pixel_out |= (pixel_in & 0xf0);
}
else
{
/* priority mode write */
pixel_out = gfx.lut_prio[priority][pixel_in >> 4][pixel_out];
pixel_out = (pixel_out << 4) | (pixel_in & 0x0f);
}
/* write data to image buffer */
WRITE_BYTE(Pico_mcd->word_ram2M, bufferIndex >> 1, pixel_out);
/* check current pixel position */
if ((bufferIndex & 7) != 7)
{
/* next pixel */
bufferIndex++;
}
else
{
/* next cell: increment image buffer offset by one column (minus 7 pixels) */
bufferIndex += gfx.bufferOffset;
}
/* increment pixel position */
xpos += xoffset;
ypos += yoffset;
pixel_out = 0;
if (xoffset+(1U<<10) <= 1U<<11 && yoffset+(1U<<10) <= 1U<<11) {
/* upscaling >= 2x, test for duplicate pixels to avoid recalculation */
uint32 oldx, oldy;
oldx = oldy = ~xpos;
RENDER_LOOP(1, oldx = xpos;oldy = ypos, (oldx^xpos ^ oldy^ypos) >> 11, (!priority) | pixel_out);
} else {
RENDER_LOOP(3, , 1, (!priority) | pixel_out);
}
}
void gfx_start(unsigned int base)
void gfx_start(uint32 base)
{
/* make sure 2M mode is enabled */
if (!(Pico_mcd->s68k_regs[3] & 0x04))
@ -327,28 +356,32 @@ void gfx_start(unsigned int base)
{
case 0:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.stampMask = 0x7ff; /* 16x16 dots/stamp */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamp */
gfx.mapShift = 4; /* 16x16 stamps/map */
mask = 0x3fe00; /* 512 bytes/table */
break;
case 1:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.stampMask = 0x7fc; /* 16x16 dots/stamp */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamp */
gfx.mapShift = 3; /* 8x8 stamps/map */
mask = 0x3ff80; /* 128 bytes/table */
break;
case 2:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.stampMask = 0x7ff; /* 16x16 dots/stamp */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamp */
gfx.mapShift = 8; /* 256x256 stamps/map */
mask = 0x20000; /* 131072 bytes/table */
break;
case 3:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.stampMask = 0x7fc; /* 16x16 dots/stamp */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamp */
gfx.mapShift = 7; /* 128x128 stamps/map */
mask = 0x38000; /* 32768 bytes/table */
break;
@ -376,6 +409,8 @@ void gfx_start(unsigned int base)
/* start graphics operation */
Pico_mcd->s68k_regs[0x58] = 0x80;
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
Pico_mcd->m.s68k_poll_cnt = 0;
gfx_schedule();
}
@ -393,10 +428,9 @@ static void gfx_schedule(void)
h = (Pico_mcd->s68k_regs[0x64] << 8) | Pico_mcd->s68k_regs[0x65];
cycles = 5 * w * h;
y_step = h;
if (cycles > UPDATE_CYCLES)
y_step = (UPDATE_CYCLES + 5 * w - 1) / (5 * w);
else
y_step = h;
gfx.y_step = y_step;
pcd_event_schedule_s68k(PCD_EVENT_GFX, 5 * w * y_step);
@ -419,9 +453,11 @@ void gfx_update(unsigned int cycles)
Pico_mcd->s68k_regs[0x64] =
Pico_mcd->s68k_regs[0x65] = 0;
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
Pico_mcd->m.s68k_poll_cnt = 0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN1) {
elprintf(EL_INTS|EL_CD, "s68k: gfx_cd irq 1");
SekInterruptS68k(1);
pcd_irq_s68k(1, 1);
}
}
else {
@ -434,7 +470,7 @@ void gfx_update(unsigned int cycles)
pcd_event_schedule(cycles, PCD_EVENT_GFX, 5 * w * lines);
}
if (PicoOpt & POPT_EN_MCD_GFX)
if (PicoIn.opt & POPT_EN_MCD_GFX)
{
/* render lines */
while (lines--)

View file

@ -10,15 +10,11 @@
#include "cell_map.c"
#ifndef UTYPES_DEFINED
typedef unsigned short u16;
#endif
// check: Heart of the alien, jaguar xj 220
PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, unsigned char inc)
PICO_INTERNAL void DmaSlowCell(u32 source, u32 a, int len, unsigned char inc)
{
unsigned char *base;
unsigned int asrc, a2;
u32 asrc, a2;
u16 *r;
base = Pico_mcd->word_ram1M[Pico_mcd->s68k_regs[3]&1];
@ -26,23 +22,22 @@ PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, uns
switch (Pico.video.type)
{
case 1: // vram
r = Pico.vram;
r = PicoMem.vram;
for(; len; len--)
{
asrc = cell_map(source >> 2) << 2;
asrc |= source & 2;
// if(a&1) d=(d<<8)|(d>>8); // ??
r[a>>1] = *(u16 *)(base + asrc);
VideoWriteVRAM(a, *(u16 *)(base + asrc));
source += 2;
// AutoIncrement
a=(u16)(a+inc);
}
rendstatus |= PDRAW_SPRITES_MOVED;
break;
case 3: // cram
Pico.m.dirtyPal = 1;
r = Pico.cram;
r = PicoMem.cram;
for(a2=a&0x7f; len; len--)
{
asrc = cell_map(source >> 2) << 2;
@ -58,7 +53,7 @@ PICO_INTERNAL void DmaSlowCell(unsigned int source, unsigned int a, int len, uns
break;
case 5: // vsram[a&0x003f]=d;
r = Pico.vsram;
r = PicoMem.vsram;
for(a2=a&0x7f; len; len--)
{
asrc = cell_map(source >> 2) << 2;

1
pico/cd/libchdr Submodule

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

View file

@ -1,6 +1,7 @@
/*
* PicoDrive
* (C) notaz, 2007,2013
* (C) irixxxx, 2019-2024
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
@ -12,12 +13,11 @@
extern unsigned char formatted_bram[4*0x10];
static unsigned int mcd_m68k_cycle_mult;
static unsigned int mcd_s68k_cycle_mult;
static unsigned int mcd_m68k_cycle_base;
static unsigned int mcd_s68k_cycle_base;
void (*PicoMCDopenTray)(void) = NULL;
void (*PicoMCDcloseTray)(void) = NULL;
mcd_state *Pico_mcd;
PICO_INTERNAL void PicoInitMCD(void)
{
@ -26,13 +26,21 @@ PICO_INTERNAL void PicoInitMCD(void)
PICO_INTERNAL void PicoExitMCD(void)
{
cdd_unload();
if (Pico_mcd) {
plat_munmap(Pico_mcd, sizeof(mcd_state));
Pico_mcd = NULL;
}
}
PICO_INTERNAL void PicoPowerMCD(void)
{
int fmt_size;
SekResetS68k();
SekCycleCntS68k = SekCycleAimS68k = 0;
int fmt_size = sizeof(formatted_bram);
fmt_size = sizeof(formatted_bram);
memset(Pico_mcd->prg_ram, 0, sizeof(Pico_mcd->prg_ram));
memset(Pico_mcd->word_ram2M, 0, sizeof(Pico_mcd->word_ram2M));
memset(Pico_mcd->pcm_ram, 0, sizeof(Pico_mcd->pcm_ram));
@ -50,7 +58,8 @@ PICO_INTERNAL void PicoPowerMCD(void)
Pico_mcd->m.state_flags = PCD_ST_S68K_RST;
Pico_mcd->m.busreq = 2; // busreq on, s68k in reset
Pico_mcd->s68k_regs[3] = 1; // 2M word RAM mode, m68k access
memset(Pico_mcd->bios + 0x70, 0xff, 4);
if (Pico.romsize <= 0x20000) // hack to detect BIOS, no GA HINT vector for MSU
memset(Pico.rom + 0x70, 0xff, 4);
}
void pcd_soft_reset(void)
@ -76,45 +85,20 @@ PICO_INTERNAL int PicoResetMCD(void)
{
// reset button doesn't affect MCD hardware
// use SRam.data for RAM cart
if (PicoOpt & POPT_EN_MCD_RAMCART) {
if (SRam.data == NULL)
SRam.data = calloc(1, 0x12000);
// use Pico.sv.data for RAM cart
if (PicoIn.opt & POPT_EN_MCD_RAMCART) {
if (Pico.sv.data == NULL)
Pico.sv.data = calloc(1, 0x12000);
}
else if (SRam.data != NULL) {
free(SRam.data);
SRam.data = NULL;
else if (Pico.sv.data != NULL) {
free(Pico.sv.data);
Pico.sv.data = NULL;
}
SRam.start = SRam.end = 0; // unused
Pico.sv.start = Pico.sv.end = 0; // unused
return 0;
}
static void SekRunM68kOnce(void)
{
int cyc_do;
pevt_log_m68k_o(EVT_RUN_START);
if ((cyc_do = SekCycleAim - SekCycleCnt) > 0) {
SekCycleCnt += cyc_do;
#if defined(EMU_C68K)
PicoCpuCM68k.cycles = cyc_do;
CycloneRun(&PicoCpuCM68k);
SekCycleCnt -= PicoCpuCM68k.cycles;
#elif defined(EMU_M68K)
SekCycleCnt += m68k_execute(cyc_do) - cyc_do;
#elif defined(EMU_F68K)
SekCycleCnt += fm68k_emulate(cyc_do, 0) - cyc_do;
#endif
}
SekCyclesLeft = 0;
SekTrace(0);
pevt_log_m68k_o(EVT_RUN_END);
}
static void SekRunS68k(unsigned int to)
{
int cyc_do;
@ -123,9 +107,7 @@ static void SekRunS68k(unsigned int to)
if ((cyc_do = SekCycleAimS68k - SekCycleCntS68k) <= 0)
return;
if (SekShouldInterrupt())
Pico_mcd->m.s68k_poll_a = 0;
pprof_start(s68k);
SekCycleCntS68k += cyc_do;
#if defined(EMU_C68K)
PicoCpuCS68k.cycles = cyc_do;
@ -136,19 +118,19 @@ static void SekRunS68k(unsigned int to)
SekCycleCntS68k += m68k_execute(cyc_do) - cyc_do;
m68k_set_context(&PicoCpuMM68k);
#elif defined(EMU_F68K)
g_m68kcontext = &PicoCpuFS68k;
SekCycleCntS68k += fm68k_emulate(cyc_do, 0) - cyc_do;
g_m68kcontext = &PicoCpuFM68k;
SekCycleCntS68k += fm68k_emulate(&PicoCpuFS68k, cyc_do, 0) - cyc_do;
#endif
SekCyclesLeftS68k = 0;
pprof_end(s68k);
}
static void pcd_set_cycle_mult(void)
void PicoMCDPrepare(void)
{
// ~1.63 for NTSC, ~1.645 for PAL
if (Pico.m.pal)
mcd_m68k_cycle_mult = ((12500000ull << 16) / (50*312*488));
else
mcd_m68k_cycle_mult = ((12500000ull << 16) / (60*262*488)) + 1;
#define DIV_ROUND(x,y) ((x)+(y)/2) / (y) // round to nearest, x/y+0.5 -> (x+y/2)/y
unsigned int osc = (Pico.m.pal ? OSC_PAL : OSC_NTSC);
mcd_m68k_cycle_mult = DIV_ROUND(12500000ull << 16, osc / 7);
mcd_s68k_cycle_mult = DIV_ROUND(1ull * osc << 16, 7 * 12500000);
}
unsigned int pcd_cycles_m68k_to_s68k(unsigned int c)
@ -168,9 +150,9 @@ static void pcd_cdc_event(unsigned int now)
/* reset CDD command wait flag */
Pico_mcd->s68k_regs[0x4b] = 0xf0;
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {
if ((Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) && (Pico_mcd->s68k_regs[0x37] & 4)) {
elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
SekInterruptS68k(4);
pcd_irq_s68k(4, 1);
}
}
@ -181,12 +163,12 @@ static void pcd_int3_timer_event(unsigned int now)
{
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN3) {
elprintf(EL_INTS|EL_CD, "s68k: timer irq 3");
SekInterruptS68k(3);
pcd_irq_s68k(3, 1);
}
if (Pico_mcd->s68k_regs[0x31] != 0)
pcd_event_schedule(now, PCD_EVENT_TIMER3,
Pico_mcd->s68k_regs[0x31] * 384);
(Pico_mcd->s68k_regs[0x31]+1) * 384);
}
static void pcd_dma_event(unsigned int now)
@ -200,23 +182,23 @@ typedef void (event_cb)(unsigned int now);
unsigned int pcd_event_times[PCD_EVENT_COUNT];
static unsigned int event_time_next;
static event_cb *pcd_event_cbs[PCD_EVENT_COUNT] = {
[PCD_EVENT_CDC] = pcd_cdc_event,
[PCD_EVENT_TIMER3] = pcd_int3_timer_event,
[PCD_EVENT_GFX] = gfx_update,
[PCD_EVENT_DMA] = pcd_dma_event,
pcd_cdc_event, // PCD_EVENT_CDC
pcd_int3_timer_event, // PCD_EVENT_TIMER3
gfx_update, // PCD_EVENT_GFX
pcd_dma_event, // PCD_EVENT_DMA
};
void pcd_event_schedule(unsigned int now, enum pcd_event event, int after)
{
unsigned int when;
when = now + after;
if (when == 0) {
if ((now|after) == 0) {
// event cancelled
pcd_event_times[event] = 0;
return;
}
when = now + after;
when |= 1;
elprintf(EL_CD, "cd: new event #%u %u->%u", event, now, when);
@ -228,8 +210,7 @@ void pcd_event_schedule(unsigned int now, enum pcd_event event, int after)
void pcd_event_schedule_s68k(enum pcd_event event, int after)
{
if (SekCyclesLeftS68k > after)
SekEndRunS68k(after);
SekEndRunS68k(after);
pcd_event_schedule(SekCyclesDoneS68k(), event, after);
}
@ -273,6 +254,16 @@ static void pcd_run_events(unsigned int until)
oldest, event_time_next);
}
void pcd_irq_s68k(int irq, int state)
{
if (state) {
SekInterruptS68k(irq);
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
Pico_mcd->m.s68k_poll_cnt = 0;
} else
SekInterruptClearS68k(irq);
}
int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
{
#define now SekCycleCntS68k
@ -288,7 +279,7 @@ int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
if (Pico_mcd->m.busreq != 1) { /* busreq/reset */
SekCycleCntS68k = SekCycleAimS68k = s68k_target;
pcd_run_events(m68k_target);
pcd_run_events(s68k_target);
return 0;
}
@ -300,7 +291,11 @@ int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
if (event_time_next && CYCLES_GT(target, event_time_next))
target = event_time_next;
SekRunS68k(target);
if (Pico_mcd->m.state_flags & (PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP))
SekCycleCntS68k = SekCycleAimS68k = target;
else
SekRunS68k(target);
if (m68k_poll_sync && Pico_mcd->m.m68k_poll_cnt == 0)
break;
}
@ -312,43 +307,61 @@ int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
#define pcd_run_cpus_normal pcd_run_cpus
//#define pcd_run_cpus_lockstep pcd_run_cpus
static void SekSyncM68k(void);
static void SekAimM68k(int cyc, int mult);
static int SekSyncM68k(int once);
void pcd_run_cpus_normal(int m68k_cycles)
{
SekCycleAim += m68k_cycles;
if (SekShouldInterrupt() || Pico_mcd->m.m68k_poll_cnt < 12)
Pico_mcd->m.m68k_poll_cnt = 0;
else if (Pico_mcd->m.m68k_poll_cnt >= 16) {
int s68k_left = pcd_sync_s68k(SekCycleAim, 1);
if (s68k_left <= 0) {
// TODO this is suspicious. ~1 cycle refresh delay every 256 cycles?
SekAimM68k(m68k_cycles, 0x42); // Fhey area
while (CYCLES_GT(Pico.t.m68c_aim, Pico.t.m68c_cnt)) {
if (SekShouldInterrupt()) {
Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;
Pico_mcd->m.m68k_poll_cnt = 0;
}
#ifdef USE_POLL_DETECT
if (Pico_mcd->m.state_flags & PCD_ST_M68K_POLL) {
int s68k_left;
// main CPU is polling, (wake and) run sub only
if (Pico_mcd->m.state_flags & (PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP)) {
Pico_mcd->m.state_flags &= ~(PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP);
Pico_mcd->m.s68k_poll_cnt = 0;
}
s68k_left = pcd_sync_s68k(Pico.t.m68c_aim, 1);
Pico.t.m68c_cnt = Pico.t.m68c_aim;
if (s68k_left > 0)
Pico.t.m68c_cnt -= ((long long)s68k_left * mcd_s68k_cycle_mult >> 16);
if (Pico_mcd->m.state_flags & (PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP)) {
// slave has stopped, wake master to avoid lockups
Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;
Pico_mcd->m.m68k_poll_cnt = 0;
}
elprintf(EL_CDPOLL, "m68k poll [%02x] x%d @%06x",
Pico_mcd->m.m68k_poll_a, Pico_mcd->m.m68k_poll_cnt, SekPc);
SekCycleCnt = SekCycleAim;
return;
}
SekCycleCnt = SekCycleAim - (s68k_left * 40220 >> 16);
}
while (CYCLES_GT(SekCycleAim, SekCycleCnt)) {
SekRunM68kOnce();
if (Pico_mcd->m.need_sync) {
Pico_mcd->m.need_sync = 0;
pcd_sync_s68k(SekCycleCnt, 0);
} else
#endif
SekSyncM68k(1);
if (Pico_mcd->m.state_flags & PCD_ST_S68K_SYNC) {
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_SYNC;
pcd_sync_s68k(Pico.t.m68c_cnt, 0);
}
}
}
void pcd_run_cpus_lockstep(int m68k_cycles)
{
unsigned int target = SekCycleAim + m68k_cycles;
unsigned int target = Pico.t.m68c_aim + m68k_cycles;
do {
SekCycleAim += 8;
SekSyncM68k();
pcd_sync_s68k(SekCycleAim, 0);
} while (CYCLES_GT(target, SekCycleAim));
Pico.t.m68c_aim += 8;
SekSyncM68k(0);
pcd_sync_s68k(Pico.t.m68c_aim, 0);
} while (CYCLES_GT(target, Pico.t.m68c_aim));
SekCycleAim = target;
Pico.t.m68c_aim = target;
}
#define PICO_CD
@ -360,11 +373,9 @@ void pcd_run_cpus_lockstep(int m68k_cycles)
void pcd_prepare_frame(void)
{
pcd_set_cycle_mult();
// need this because we can't have direct mapping between
// master<->slave cycle counters because of overflows
mcd_m68k_cycle_base = SekCycleAim;
mcd_m68k_cycle_base = Pico.t.m68c_aim;
mcd_s68k_cycle_base = SekCycleAimS68k;
}
@ -381,7 +392,6 @@ void pcd_state_loaded(void)
unsigned int cycles;
int diff;
pcd_set_cycle_mult();
pcd_state_loaded_mem();
memset(Pico_mcd->pcm_mixbuf, 0, sizeof(Pico_mcd->pcm_mixbuf));
@ -390,9 +400,8 @@ void pcd_state_loaded(void)
Pico_mcd->pcm_regs_dirty = 1;
// old savestates..
cycles = pcd_cycles_m68k_to_s68k(SekCycleAim);
diff = cycles - SekCycleAimS68k;
if (diff < -1000 || diff > 1000) {
cycles = pcd_cycles_m68k_to_s68k(Pico.t.m68c_aim);
if (CYCLES_GE(cycles - SekCycleAimS68k, 1000)) {
SekCycleCntS68k = SekCycleAimS68k = cycles;
}
if (pcd_event_times[PCD_EVENT_CDC] == 0) {
@ -407,6 +416,11 @@ void pcd_state_loaded(void)
if ((unsigned int)diff > 12500000/50)
Pico_mcd->pcm.update_cycles = cycles;
if (Pico_mcd->m.need_sync) {
Pico_mcd->m.state_flags |= PCD_ST_S68K_SYNC;
Pico_mcd->m.need_sync = 0;
}
// reschedule
event_time_next = 0;
pcd_run_events(SekCycleCntS68k);

View file

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

View file

@ -1,6 +1,7 @@
/*
* Memory I/O handlers for Sega/Mega CD.
* (C) notaz, 2007-2009
* (C) irixxxx, 2019-2024
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
@ -14,12 +15,17 @@ uptr s68k_read16_map [0x1000000 >> M68K_MEM_SHIFT];
uptr s68k_write8_map [0x1000000 >> M68K_MEM_SHIFT];
uptr s68k_write16_map[0x1000000 >> M68K_MEM_SHIFT];
#ifndef _ASM_CD_MEMORY_C
MAKE_68K_READ8(s68k_read8, s68k_read8_map)
MAKE_68K_READ16(s68k_read16, s68k_read16_map)
MAKE_68K_READ32(s68k_read32, s68k_read16_map)
MAKE_68K_WRITE8(s68k_write8, s68k_write8_map)
MAKE_68K_WRITE16(s68k_write16, s68k_write16_map)
MAKE_68K_WRITE32(s68k_write32, s68k_write16_map)
#endif
u32 pcd_base_address;
#define BASE pcd_base_address
// -----------------------------------------------------------------
@ -66,20 +72,36 @@ static void remap_word_ram(u32 r3);
void m68k_comm_check(u32 a)
{
pcd_sync_s68k(SekCyclesDone(), 0);
if (a >= 0x0e && !Pico_mcd->m.need_sync) {
u32 cycles = SekCyclesDone();
u32 clkdiff = cycles - Pico_mcd->m.m68k_poll_clk;
pcd_sync_s68k(cycles, 0);
if (a == 0x0e && !(Pico_mcd->m.state_flags & PCD_ST_S68K_SYNC) && (Pico_mcd->s68k_regs[3]&0x4)) {
// there are cases when slave updates comm and only switches RAM
// over after that (mcd1b), so there must be a resync..
// over after that (mcd1 bios), so there must be a resync..
SekEndRun(64);
Pico_mcd->m.need_sync = 1;
Pico_mcd->m.state_flags |= PCD_ST_S68K_SYNC;
}
if (SekNotPolling || a != Pico_mcd->m.m68k_poll_a) {
Pico_mcd->m.m68k_poll_clk = cycles;
if (SekNotPolling || a != Pico_mcd->m.m68k_poll_a || clkdiff > POLL_CYCLES || clkdiff <= 16) {
Pico_mcd->m.m68k_poll_a = a;
Pico_mcd->m.m68k_poll_cnt = 0;
SekNotPolling = 0;
return;
}
Pico_mcd->m.m68k_poll_cnt++;
Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;
if (Pico_mcd->m.m68k_poll_cnt >= POLL_LIMIT) {
Pico_mcd->m.state_flags |= PCD_ST_M68K_POLL;
SekEndRun(8);
}
}
u32 pcd_stopwatch_read(int sub)
{
// ugh... stopwatch runs 384 cycles per step, divide by mult with inverse
u32 d = sub ? SekCyclesDoneS68k() : pcd_cycles_m68k_to_s68k(SekCyclesDone());
d = ((d - Pico_mcd->m.stopwatch_base_c) * ((1LL << 32) / 384)) >> 32;
return d & 0x0fff;
}
#ifndef _ASM_CD_MEMORY_C
@ -90,9 +112,9 @@ static u32 m68k_reg_read16(u32 a)
switch (a) {
case 0:
// here IFL2 is always 0, just like in Gens
d = ((Pico_mcd->s68k_regs[0x33] << 13) & 0x8000)
| Pico_mcd->m.busreq;
pcd_sync_s68k(SekCyclesDone(), 0);
d = ((Pico_mcd->s68k_regs[0x33] & PCDS_IEN2) << 13) |
(Pico_mcd->m.state_flags & PCD_ST_S68K_IFL2) | Pico_mcd->m.busreq;
goto end;
case 2:
m68k_comm_check(a);
@ -103,19 +125,16 @@ static u32 m68k_reg_read16(u32 a)
d = Pico_mcd->s68k_regs[4]<<8;
goto end;
case 6:
d = *(u16 *)(Pico_mcd->bios + 0x72);
d = *(u16 *)(Pico.rom + 0x72);
goto end;
case 8:
d = cdc_host_r();
goto end;
case 0xA:
case 0xa:
elprintf(EL_UIO, "m68k FIXME: reserved read");
goto end;
case 0xC: // 384 cycle stopwatch timer
// ugh..
d = pcd_cycles_m68k_to_s68k(SekCyclesDone());
d = (d - Pico_mcd->m.stopwatch_base_c) / 384;
d &= 0x0fff;
case 0xc: // 384 cycle stopwatch timer
d = pcd_stopwatch_read(0);
elprintf(EL_CDREGS, "m68k stopwatch timer read (%04x)", d);
goto end;
}
@ -124,7 +143,7 @@ static u32 m68k_reg_read16(u32 a)
// comm flag/cmd/status (0xE-0x2F)
m68k_comm_check(a);
d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1];
goto end;
return d;
}
elprintf(EL_UIO, "m68k_regs FIXME invalid read @ %02x", a);
@ -142,20 +161,27 @@ void m68k_reg_write8(u32 a, u32 d)
u32 dold;
a &= 0x3f;
Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;
Pico_mcd->m.m68k_poll_cnt = 0;
switch (a) {
case 0:
d &= 1;
pcd_sync_s68k(SekCyclesDone(), 0);
if (d && (Pico_mcd->s68k_regs[0x33] & PCDS_IEN2)) {
elprintf(EL_INTS, "m68k: s68k irq 2");
pcd_sync_s68k(SekCyclesDone(), 0);
SekInterruptS68k(2);
Pico_mcd->m.state_flags |= PCD_ST_S68K_IFL2;
pcd_irq_s68k(2, 1);
} else {
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_IFL2;
pcd_irq_s68k(2, 0);
}
return;
case 1:
d &= 3;
dold = Pico_mcd->m.busreq;
if (!(d & 1))
d |= 2; // verified: can't release bus on reset
// if (!(d & 1))
// d |= 2; // verified: can't release bus on reset
if (dold == d)
return;
@ -166,11 +192,12 @@ void m68k_reg_write8(u32 a, u32 d)
if (!(d & 1))
Pico_mcd->m.state_flags |= PCD_ST_S68K_RST;
else if (d == 1 && (Pico_mcd->m.state_flags & PCD_ST_S68K_RST)) {
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_RST;
Pico_mcd->m.state_flags &= ~(PCD_ST_S68K_RST|PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP);
elprintf(EL_CDREGS, "m68k: resetting s68k");
SekResetS68k();
SekCycleCntS68k += 40;
}
if ((dold ^ d) & 2) {
if (((dold & 3) == 1) != ((d & 3) == 1)) {
elprintf(EL_INTSW, "m68k: s68k brq %i", d >> 1);
remap_prg_window(d, Pico_mcd->s68k_regs[3]);
}
@ -178,11 +205,10 @@ void m68k_reg_write8(u32 a, u32 d)
return;
case 2:
elprintf(EL_CDREGS, "m68k: prg wp=%02x", d);
Pico_mcd->s68k_regs[2] = d; // really use s68k side register
return;
goto write_comm;
case 3:
dold = Pico_mcd->s68k_regs[3];
elprintf(EL_CDREG3, "m68k_regs w3: %02x @%06x", (u8)d, SekPc);
dold = Pico_mcd->s68k_regs[3];
if ((d ^ dold) & 0xc0) {
elprintf(EL_CDREGS, "m68k: prg bank: %i -> %i",
(Pico_mcd->s68k_regs[a]>>6), ((d>>6)&3));
@ -200,15 +226,19 @@ void m68k_reg_write8(u32 a, u32 d)
}
else
d = (d & 0xc0) | (dold & 0x1c) | Pico_mcd->m.dmna_ret_2m;
if ((dold ^ d) & 0x1f)
remap_word_ram(d);
goto write_comm;
case 6:
Pico_mcd->bios[0x72 + 1] = d; // simple hint vector changer
Pico.rom[MEM_BE2(0x72)] = d; // simple hint vector changer
return;
case 7:
Pico_mcd->bios[0x72] = d;
Pico.rom[MEM_BE2(0x73)] = d;
elprintf(EL_CDREGS, "hint vector set to %04x%04x",
((u16 *)Pico_mcd->bios)[0x70/2], ((u16 *)Pico_mcd->bios)[0x72/2]);
((u16 *)Pico.rom)[0x70/2], ((u16 *)Pico.rom)[0x72/2]);
return;
case 8:
(void) cdc_host_r(); // acts same as reading
return;
case 0x0f:
a = 0x0e;
@ -223,18 +253,23 @@ void m68k_reg_write8(u32 a, u32 d)
return;
write_comm:
if (d == Pico_mcd->s68k_regs[a])
if (Pico_mcd->s68k_regs[a] == (u8)d)
return;
pcd_sync_s68k(SekCyclesDone(), 0);
Pico_mcd->s68k_regs[a] = d;
if (Pico_mcd->m.s68k_poll_a == (a & ~1))
{
if (Pico_mcd->m.s68k_poll_cnt > POLL_LIMIT) {
if (a == 0x03) {
// There are cases when master checks for successful switching of RAM to
// slave. This can produce race conditions where slave switches RAM back to
// master while master is delayed by interrupt before the check executes.
// Delay slave a bit to make sure master can check before slave changes.
SekCycleCntS68k += 24; // Silpheed
}
if (!((Pico_mcd->m.s68k_poll_a ^ a) & ~1)) {
if (Pico_mcd->m.state_flags & PCD_ST_S68K_POLL)
elprintf(EL_CDPOLL, "s68k poll release, a=%02x", a);
SekSetStopS68k(0);
}
Pico_mcd->m.s68k_poll_a = 0;
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
Pico_mcd->m.s68k_poll_cnt = 0;
}
}
@ -242,20 +277,23 @@ u32 s68k_poll_detect(u32 a, u32 d)
{
#ifdef USE_POLL_DETECT
u32 cycles, cnt = 0;
if (SekIsStoppedS68k())
if (Pico_mcd->m.state_flags & (PCD_ST_S68K_POLL|PCD_ST_S68K_SLEEP))
return d;
cycles = SekCyclesDoneS68k();
if (!SekNotPolling && a == Pico_mcd->m.s68k_poll_a) {
if (!SekNotPollingS68k && a == Pico_mcd->m.s68k_poll_a) {
u32 clkdiff = cycles - Pico_mcd->m.s68k_poll_clk;
if (clkdiff <= POLL_CYCLES) {
cnt = Pico_mcd->m.s68k_poll_cnt + 1;
//printf("-- diff: %u, cnt = %i\n", clkdiff, cnt);
if (Pico_mcd->m.s68k_poll_cnt > POLL_LIMIT) {
SekSetStopS68k(1);
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
if (cnt > POLL_LIMIT) {
Pico_mcd->m.state_flags |= PCD_ST_S68K_POLL;
SekEndRunS68k(8);
elprintf(EL_CDPOLL, "s68k poll detected @%06x, a=%02x",
SekPcS68k, a);
}
} else if (cnt > 2)
SekEndRunS68k(240);
}
}
Pico_mcd->m.s68k_poll_a = a;
@ -268,7 +306,7 @@ u32 s68k_poll_detect(u32 a, u32 d)
#define READ_FONT_DATA(basemask) \
{ \
unsigned int fnt = *(unsigned int *)(Pico_mcd->s68k_regs + 0x4c); \
unsigned int fnt = CPU_LE4(*(u32 *)(Pico_mcd->s68k_regs + 0x4c)); \
unsigned int col0 = (fnt >> 8) & 0x0f, col1 = (fnt >> 12) & 0x0f; \
if (fnt & (basemask << 0)) d = col1 ; else d = col0; \
if (fnt & (basemask << 1)) d |= col1 << 4; else d |= col0 << 4; \
@ -286,45 +324,53 @@ u32 s68k_reg_read16(u32 a)
switch (a) {
case 0:
return ((Pico_mcd->s68k_regs[0]&3)<<8) | 1; // ver = 0, not in reset state
d = ((Pico_mcd->s68k_regs[0]&3)<<8) | 1; // ver = 0, not in reset state
goto end;
case 2:
d = (Pico_mcd->s68k_regs[2]<<8) | (Pico_mcd->s68k_regs[3]&0x1f);
elprintf(EL_CDREG3, "s68k_regs r3: %02x @%06x", (u8)d, SekPcS68k);
return s68k_poll_detect(a, d);
s68k_poll_detect(a, d);
goto end;
case 4:
d = (Pico_mcd->s68k_regs[4]<<8) | (Pico_mcd->s68k_regs[5]&0x1f);
goto end;
case 6:
return cdc_reg_r();
d = cdc_reg_r();
goto end;
case 8:
return cdc_host_r();
case 0xC:
d = SekCyclesDoneS68k() - Pico_mcd->m.stopwatch_base_c;
d /= 384;
d &= 0x0fff;
d = cdc_host_r();
goto end;
case 0xc:
d = pcd_stopwatch_read(1);
elprintf(EL_CDREGS, "s68k stopwatch timer read (%04x)", d);
return d;
goto end;
case 0x30:
elprintf(EL_CDREGS, "s68k int3 timer read (%02x)", Pico_mcd->s68k_regs[31]);
return Pico_mcd->s68k_regs[31];
elprintf(EL_CDREGS, "s68k int3 timer read (%02x)", Pico_mcd->s68k_regs[0x31]);
d = Pico_mcd->s68k_regs[0x31];
goto end;
case 0x34: // fader
return 0; // no busy bit
d = 0; // no busy bit
goto end;
case 0x50: // font data (check: Lunar 2, Silpheed)
READ_FONT_DATA(0x00100000);
return d;
goto end;
case 0x52:
READ_FONT_DATA(0x00010000);
return d;
goto end;
case 0x54:
READ_FONT_DATA(0x10000000);
return d;
goto end;
case 0x56:
READ_FONT_DATA(0x01000000);
return d;
goto end;
}
d = (Pico_mcd->s68k_regs[a]<<8) | Pico_mcd->s68k_regs[a+1];
if (a >= 0x0e && a < 0x30)
return s68k_poll_detect(a, d);
if ((a >= 0x0e && a < 0x30) || a == 0x58)
d = s68k_poll_detect(a, d);
end:
return d;
}
@ -339,8 +385,7 @@ void s68k_reg_write8(u32 a, u32 d)
if (!(d & 1))
pcd_soft_reset();
return;
case 2:
return; // only m68k can change WP
case 2: a++; // byte access only, ignores LDS/UDS
case 3: {
int dold = Pico_mcd->s68k_regs[3];
elprintf(EL_CDREG3, "s68k_regs w3: %02x @%06x", (u8)d, SekPcS68k);
@ -360,9 +405,6 @@ void s68k_reg_write8(u32 a, u32 d)
wram_2M_to_1M(Pico_mcd->word_ram2M);
}
if ((d ^ dold) & 0x1d)
remap_word_ram(d);
if ((d ^ dold) & 0x05)
d &= ~2; // clear DMNA - swap complete
}
@ -371,54 +413,62 @@ void s68k_reg_write8(u32 a, u32 d)
if (dold & 4) {
elprintf(EL_CDREG3, "wram mode 1M->2M");
wram_1M_to_2M(Pico_mcd->word_ram2M);
remap_word_ram(d);
}
d = (d & ~3) | Pico_mcd->m.dmna_ret_2m;
}
if ((dold ^ d) & 0x1f)
remap_word_ram(d);
goto write_comm;
}
case 4:
elprintf(EL_CDREGS, "s68k CDC dest: %x", d&7);
Pico_mcd->s68k_regs[4] = (Pico_mcd->s68k_regs[4]&0xC0) | (d&7); // CDC mode
Pico_mcd->s68k_regs[a] = (d&7); // CDC mode
Pico_mcd->s68k_regs[0xa] = Pico_mcd->s68k_regs[0xb] = 0; // resets DMA
return;
case 5:
//dprintf("s68k CDC reg addr: %x", d&0xf);
break;
//dprintf("s68k CDC reg addr: %x", d&0x1f);
Pico_mcd->s68k_regs[a] = (d&0x1f);
return;
case 7:
cdc_reg_w(d & 0xff);
return;
case 0xa:
case 0xb:
// word access only. 68k sets both bus halves to value d.
elprintf(EL_CDREGS, "s68k set CDC dma addr");
break;
Pico_mcd->s68k_regs[0xa] = Pico_mcd->s68k_regs[0xb] = d;
return;
case 0xc:
case 0xd: // 384 cycle stopwatch timer
elprintf(EL_CDREGS|EL_CD, "s68k clear stopwatch (%x)", d);
// does this also reset internal 384 cycle counter?
Pico_mcd->m.stopwatch_base_c = SekCyclesDoneS68k();
return;
case 0x0e:
a = 0x0f;
case 0x0e: a++;
case 0x0f:
goto write_comm;
case 0x30: a++;
case 0x31: // 384 cycle int3 timer
d &= 0xff;
elprintf(EL_CDREGS|EL_CD, "s68k set int3 timer: %02x", d);
Pico_mcd->s68k_regs[a] = (u8) d;
if (d) // d or d+1??
pcd_event_schedule_s68k(PCD_EVENT_TIMER3, d * 384);
if (d) // XXX: d or d+1? mcd-verificator results suggest d+1
pcd_event_schedule_s68k(PCD_EVENT_TIMER3, (d+1) * 384);
else
pcd_event_schedule(0, PCD_EVENT_TIMER3, 0);
break;
case 0x33: // IRQ mask
elprintf(EL_CDREGS|EL_CD, "s68k irq mask: %02x", d);
d &= 0x7e;
if ((d ^ Pico_mcd->s68k_regs[0x33]) & d & PCDS_IEN4) {
if ((d ^ Pico_mcd->s68k_regs[0x33]) & PCDS_IEN4) {
// XXX: emulate pending irq instead?
if (Pico_mcd->s68k_regs[0x37] & 4) {
if ((d & PCDS_IEN4) && (Pico_mcd->s68k_regs[0x37] & 4)) {
elprintf(EL_INTS, "cdd export irq 4 (unmask)");
SekInterruptS68k(4);
pcd_irq_s68k(4, 1);
}
}
if ((d ^ Pico_mcd->s68k_regs[0x33]) & ~d & PCDS_IEN2)
pcd_irq_s68k(2, 0);
break;
case 0x34: // fader
Pico_mcd->s68k_regs[a] = (u8) d & 0x7f;
@ -428,13 +478,14 @@ void s68k_reg_write8(u32 a, u32 d)
case 0x37: {
u32 d_old = Pico_mcd->s68k_regs[0x37];
Pico_mcd->s68k_regs[0x37] = d & 7;
if ((d&4) && !(d_old&4)) {
if ((d ^ d_old) & 4) {
// ??
pcd_event_schedule_s68k(PCD_EVENT_CDC, 12500000/75);
if (d & 4)
pcd_event_schedule_s68k(PCD_EVENT_CDC, 12500000/75);
if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {
if ((d & 4) && (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4)) {
elprintf(EL_INTS, "cdd export irq 4");
SekInterruptS68k(4);
pcd_irq_s68k(4, 1);
}
}
return;
@ -458,6 +509,8 @@ void s68k_reg_write8(u32 a, u32 d)
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9]);
}
return;
case 0x4c: a++;
break;
case 0x58:
return;
}
@ -475,24 +528,39 @@ void s68k_reg_write8(u32 a, u32 d)
return;
write_comm:
if (Pico_mcd->s68k_regs[a] == (u8)d)
return;
Pico_mcd->s68k_regs[a] = (u8) d;
if (Pico_mcd->m.m68k_poll_cnt)
SekEndRunS68k(0);
Pico_mcd->m.m68k_poll_cnt = 0;
if (!((Pico_mcd->m.m68k_poll_a ^ a) & ~1)) {
SekEndRunS68k(8);
Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;
Pico_mcd->m.m68k_poll_cnt = 0;
}
}
void s68k_reg_write16(u32 a, u32 d)
{
u8 *r = Pico_mcd->s68k_regs;
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_POLL;
Pico_mcd->m.s68k_poll_cnt = 0;
if ((a & 0x1f0) == 0x20)
goto write_comm;
switch (a) {
case 0x02:
case 0x0e:
// special case, 2 byte writes would be handled differently
// TODO: verify
r[0xf] = d;
case 0x30:
case 0x4c:
// these are only byte registers, LDS/UDS ignored
return s68k_reg_write8(a + 1, d);
case 0x08:
return (void) cdc_host_r(); // acts same as reading
case 0x0a: // DMA address
r[0xa] = d >> 8;
r[0xb] = d;
return;
case 0x58: // stamp data size
r[0x59] = d & 7;
@ -533,11 +601,16 @@ void s68k_reg_write16(u32 a, u32 d)
return;
write_comm:
if (r[a] == (u8)(d >> 8) && r[a + 1] == (u8)d)
return;
r[a] = d >> 8;
r[a + 1] = d;
if (Pico_mcd->m.m68k_poll_cnt)
SekEndRunS68k(0);
Pico_mcd->m.m68k_poll_cnt = 0;
if (!((Pico_mcd->m.m68k_poll_a ^ a) & ~1)) {
SekEndRunS68k(8);
Pico_mcd->m.state_flags &= ~PCD_ST_M68K_POLL;
Pico_mcd->m.m68k_poll_cnt = 0;
}
}
// -----------------------------------------------------------------
@ -551,13 +624,13 @@ write_comm:
static u32 PicoReadM68k8_cell0(u32 a)
{
a = (a&3) | (cell_map(a >> 2) << 2); // cell arranged
return Pico_mcd->word_ram1M[0][a ^ 1];
return Pico_mcd->word_ram1M[0][MEM_BE2(a)];
}
static u32 PicoReadM68k8_cell1(u32 a)
{
a = (a&3) | (cell_map(a >> 2) << 2);
return Pico_mcd->word_ram1M[1][a ^ 1];
return Pico_mcd->word_ram1M[1][MEM_BE2(a)];
}
static u32 PicoReadM68k16_cell0(u32 a)
@ -575,13 +648,13 @@ static u32 PicoReadM68k16_cell1(u32 a)
static void PicoWriteM68k8_cell0(u32 a, u32 d)
{
a = (a&3) | (cell_map(a >> 2) << 2);
Pico_mcd->word_ram1M[0][a ^ 1] = d;
Pico_mcd->word_ram1M[0][MEM_BE2(a)] = d;
}
static void PicoWriteM68k8_cell1(u32 a, u32 d)
{
a = (a&3) | (cell_map(a >> 2) << 2);
Pico_mcd->word_ram1M[1][a ^ 1] = d;
Pico_mcd->word_ram1M[1][MEM_BE2(a)] = d;
}
static void PicoWriteM68k16_cell0(u32 a, u32 d)
@ -597,24 +670,44 @@ static void PicoWriteM68k16_cell1(u32 a, u32 d)
}
#endif
// RAM cart (40000 - 7fffff, optional)
// BIOS faking for MSU-MD, checks for "SEGA" at 0x400100 to detect CD drive
static u8 bios_id[4] = "SEGA";
static u32 PicoReadM68k8_bios(u32 a)
{
if ((a & 0xfffffc) == BASE+0x100) // CD detection by MSU
return bios_id[a&3];
return 0;
}
static u32 PicoReadM68k16_bios(u32 a)
{
if ((a & 0xfffffc) == BASE+0x100) // CD detection by MSU
return (bios_id[a&2]<<8) | bios_id[(a&2)+1];
return 0;
}
// RAM cart (400000 - 7fffff, optional)
static u32 PicoReadM68k8_ramc(u32 a)
{
u32 d = 0;
if (a == 0x400001) {
if (SRam.data != NULL)
d = 3; // 64k cart
return d;
}
if ((a & 0xfe0000) == 0x600000) {
if (SRam.data != NULL)
d = SRam.data[((a >> 1) & 0xffff) + 0x2000];
return d;
}
if (PicoIn.opt & POPT_EN_MCD_RAMCART) {
if ((a & 0xf00001) == 0x400001) {
if (Pico.sv.data != NULL)
d = 3; // 64k cart
return d;
}
if (a == 0x7fffff)
return Pico_mcd->m.bcram_reg;
if ((a & 0xf00001) == 0x600001) {
if (Pico.sv.data != NULL)
d = Pico.sv.data[((a >> 1) & 0xffff) + 0x2000];
return d;
}
if ((a & 0xf00001) == 0x700001)
return Pico_mcd->m.bcram_reg;
}
elprintf(EL_UIO, "m68k unmapped r8 [%06x] @%06x", a, SekPc);
return d;
@ -622,23 +715,25 @@ static u32 PicoReadM68k8_ramc(u32 a)
static u32 PicoReadM68k16_ramc(u32 a)
{
elprintf(EL_ANOMALY, "ramcart r16: [%06x] @%06x", a, SekPcS68k);
elprintf(EL_ANOMALY, "ramcart r16: [%06x] @%06x", a, SekPc);
return PicoReadM68k8_ramc(a + 1);
}
static void PicoWriteM68k8_ramc(u32 a, u32 d)
{
if ((a & 0xfe0000) == 0x600000) {
if (SRam.data != NULL && (Pico_mcd->m.bcram_reg & 1)) {
SRam.data[((a>>1) & 0xffff) + 0x2000] = d;
SRam.changed = 1;
if (PicoIn.opt & POPT_EN_MCD_RAMCART) {
if ((a & 0xf00001) == 0x600001) {
if (Pico.sv.data != NULL && (Pico_mcd->m.bcram_reg & 1)) {
Pico.sv.data[((a >> 1) & 0xffff) + 0x2000] = d;
Pico.sv.changed = 1;
}
return;
}
return;
}
if (a == 0x7fffff) {
Pico_mcd->m.bcram_reg = d;
return;
if ((a & 0xf00001) == 0x700001) {
Pico_mcd->m.bcram_reg = d;
return;
}
}
elprintf(EL_UIO, "m68k unmapped w8 [%06x] %02x @%06x",
@ -745,7 +840,7 @@ static void s68k_unmapped_write16(u32 a, u32 d)
static void PicoWriteS68k8_prgwp(u32 a, u32 d)
{
if (a >= (Pico_mcd->s68k_regs[2] << 9))
Pico_mcd->prg_ram[a ^ 1] = d;
Pico_mcd->prg_ram[MEM_BE2(a)] = d;
}
static void PicoWriteS68k16_prgwp(u32 a, u32 d)
@ -759,7 +854,7 @@ static void PicoWriteS68k16_prgwp(u32 a, u32 d)
// decode (080000 - 0bffff, in 1M mode)
static u32 PicoReadS68k8_dec0(u32 a)
{
u32 d = Pico_mcd->word_ram1M[0][((a >> 1) ^ 1) & 0x1ffff];
u32 d = Pico_mcd->word_ram1M[0][MEM_BE2(a >> 1) & 0x1ffff];
if (a & 1)
d &= 0x0f;
else
@ -769,7 +864,7 @@ static u32 PicoReadS68k8_dec0(u32 a)
static u32 PicoReadS68k8_dec1(u32 a)
{
u32 d = Pico_mcd->word_ram1M[1][((a >> 1) ^ 1) & 0x1ffff];
u32 d = Pico_mcd->word_ram1M[1][MEM_BE2(a >> 1) & 0x1ffff];
if (a & 1)
d &= 0x0f;
else
@ -779,7 +874,7 @@ static u32 PicoReadS68k8_dec1(u32 a)
static u32 PicoReadS68k16_dec0(u32 a)
{
u32 d = Pico_mcd->word_ram1M[0][((a >> 1) ^ 1) & 0x1ffff];
u32 d = Pico_mcd->word_ram1M[0][MEM_BE2(a >> 1) & 0x1ffff];
d |= d << 4;
d &= ~0xf0;
return d;
@ -787,7 +882,7 @@ static u32 PicoReadS68k16_dec0(u32 a)
static u32 PicoReadS68k16_dec1(u32 a)
{
u32 d = Pico_mcd->word_ram1M[1][((a >> 1) ^ 1) & 0x1ffff];
u32 d = Pico_mcd->word_ram1M[1][MEM_BE2(a >> 1) & 0x1ffff];
d |= d << 4;
d &= ~0xf0;
return d;
@ -797,7 +892,7 @@ static u32 PicoReadS68k16_dec1(u32 a)
#define mk_decode_w8(bank) \
static void PicoWriteS68k8_dec_m0b##bank(u32 a, u32 d) \
{ \
u8 *pd = &Pico_mcd->word_ram1M[bank][((a >> 1) ^ 1) & 0x1ffff]; \
u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\
\
if (!(a & 1)) \
*pd = (*pd & 0x0f) | (d << 4); \
@ -807,7 +902,7 @@ static void PicoWriteS68k8_dec_m0b##bank(u32 a, u32 d) \
\
static void PicoWriteS68k8_dec_m1b##bank(u32 a, u32 d) \
{ \
u8 *pd = &Pico_mcd->word_ram1M[bank][((a >> 1) ^ 1) & 0x1ffff]; \
u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\
u8 mask = (a & 1) ? 0x0f : 0xf0; \
\
if (!(*pd & mask) && (d & 0x0f)) /* underwrite */ \
@ -826,7 +921,7 @@ mk_decode_w8(1)
#define mk_decode_w16(bank) \
static void PicoWriteS68k16_dec_m0b##bank(u32 a, u32 d) \
{ \
u8 *pd = &Pico_mcd->word_ram1M[bank][((a >> 1) ^ 1) & 0x1ffff]; \
u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\
\
d &= 0x0f0f; \
*pd = d | (d >> 4); \
@ -834,7 +929,7 @@ static void PicoWriteS68k16_dec_m0b##bank(u32 a, u32 d) \
\
static void PicoWriteS68k16_dec_m1b##bank(u32 a, u32 d) \
{ \
u8 *pd = &Pico_mcd->word_ram1M[bank][((a >> 1) ^ 1) & 0x1ffff]; \
u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\
\
d &= 0x0f0f; /* underwrite */ \
if (!(*pd & 0xf0)) *pd |= d >> 4; \
@ -843,7 +938,7 @@ static void PicoWriteS68k16_dec_m1b##bank(u32 a, u32 d) \
\
static void PicoWriteS68k16_dec_m2b##bank(u32 a, u32 d) \
{ \
u8 *pd = &Pico_mcd->word_ram1M[bank][((a >> 1) ^ 1) & 0x1ffff]; \
u8 *pd = &Pico_mcd->word_ram1M[bank][MEM_BE2(a >> 1) & 0x1ffff];\
\
d &= 0x0f0f; /* overwrite */ \
d |= d >> 4; \
@ -869,15 +964,16 @@ static u32 PicoReadS68k16_bram(u32 a)
u32 d;
elprintf(EL_ANOMALY, "FIXME: s68k_bram r16: [%06x] @%06x", a, SekPcS68k);
a = (a >> 1) & 0x1fff;
d = Pico_mcd->bram[a++];
d|= Pico_mcd->bram[a++] << 8; // probably wrong, TODO: verify
d = Pico_mcd->bram[a];
return d;
}
static void PicoWriteS68k8_bram(u32 a, u32 d)
{
Pico_mcd->bram[(a >> 1) & 0x1fff] = d;
SRam.changed = 1;
if (a & 1) {
Pico_mcd->bram[(a >> 1) & 0x1fff] = d;
Pico.sv.changed = 1;
}
}
static void PicoWriteS68k16_bram(u32 a, u32 d)
@ -885,8 +981,7 @@ static void PicoWriteS68k16_bram(u32 a, u32 d)
elprintf(EL_ANOMALY, "s68k_bram w16: [%06x] %04x @%06x", a, d, SekPcS68k);
a = (a >> 1) & 0x1fff;
Pico_mcd->bram[a++] = d;
Pico_mcd->bram[a++] = d >> 8; // TODO: verify..
SRam.changed = 1;
Pico.sv.changed = 1;
}
#ifndef _ASM_CD_MEMORY_C
@ -901,7 +996,7 @@ static u32 PicoReadS68k8_pr(u32 a)
a &= 0x1ff;
if (a >= 0x0e && a < 0x30) {
d = Pico_mcd->s68k_regs[a];
s68k_poll_detect(a & ~1, d);
d = s68k_poll_detect(a & ~1, d);
goto regs_done;
}
d = s68k_reg_read16(a & ~1);
@ -1031,63 +1126,85 @@ static const void *s68k_dec_write16[2][4] = {
static void remap_prg_window(u32 r1, u32 r3)
{
// PRG RAM
if (r1 & 2) {
// PRG RAM, mapped to main CPU if sub is not running
if ((r1 & 3) != 1) {
void *bank = Pico_mcd->prg_ram_b[(r3 >> 6) & 3];
cpu68k_map_all_ram(0x020000, 0x03ffff, bank, 0);
}
else {
m68k_map_unmap(0x020000, 0x03ffff);
cpu68k_map_all_ram(BASE+0x020000, BASE+0x03ffff, bank, 0);
} else {
m68k_map_unmap(BASE+0x020000, BASE+0x03ffff);
}
}
// if sub CPU accesses Word-RAM while it is assigned to the main CPU,
// GA doesn't assert DTACK, which means the CPU is blocked until the Word_RAM
// is reassigned to it (e.g. Mega Race).
// since DTACK isn't on the expansion port, main cpu accesses are not blocked.
// XXX is data read/written if main is accessing Word_RAM while not owning it?
static u32 s68k_wordram_main_read8(u32 a)
{
Pico_mcd->m.state_flags |= PCD_ST_S68K_SLEEP;
SekEndRunS68k(0);
return Pico_mcd->word_ram2M[MEM_BE2(a) & 0x3ffff];
}
static u32 s68k_wordram_main_read16(u32 a)
{
Pico_mcd->m.state_flags |= PCD_ST_S68K_SLEEP;
SekEndRunS68k(0);
return ((u16 *)Pico_mcd->word_ram2M)[(a >> 1) & 0x1ffff];
}
static void s68k_wordram_main_write8(u32 a, u32 d)
{
Pico_mcd->m.state_flags |= PCD_ST_S68K_SLEEP;
SekEndRunS68k(0);
Pico_mcd->word_ram2M[MEM_BE2(a) & 0x3ffff] = d;
}
static void s68k_wordram_main_write16(u32 a, u32 d)
{
Pico_mcd->m.state_flags |= PCD_ST_S68K_SLEEP;
SekEndRunS68k(0);
((u16 *)Pico_mcd->word_ram2M)[(a >> 1) & 0x1ffff] = d;
}
static void remap_word_ram(u32 r3)
{
void *bank;
// WORD RAM
if (!(r3 & 4)) {
// 2M mode. XXX: allowing access in all cases for simplicity
// 2M mode.
bank = Pico_mcd->word_ram2M;
cpu68k_map_all_ram(0x200000, 0x23ffff, bank, 0);
cpu68k_map_all_ram(0x080000, 0x0bffff, bank, 1);
if (r3 & 1) {
cpu68k_map_all_ram(BASE+0x200000, BASE+0x23ffff, bank, 0);
cpu68k_map_all_funcs(0x80000, 0xbffff,
s68k_wordram_main_read8, s68k_wordram_main_read16,
s68k_wordram_main_write8, s68k_wordram_main_write16, 1);
} else {
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_SLEEP;
cpu68k_map_all_ram(0x080000, 0x0bffff, bank, 1);
m68k_map_unmap(BASE+0x200000, BASE+0x23ffff);
}
// TODO: handle 0x0c0000
}
else {
int b0 = r3 & 1;
int m = (r3 & 0x18) >> 3;
Pico_mcd->m.state_flags &= ~PCD_ST_S68K_SLEEP;
bank = Pico_mcd->word_ram1M[b0];
cpu68k_map_all_ram(0x200000, 0x21ffff, bank, 0);
cpu68k_map_all_ram(BASE+0x200000, BASE+0x21ffff, bank, 0);
bank = Pico_mcd->word_ram1M[b0 ^ 1];
cpu68k_map_all_ram(0x0c0000, 0x0effff, bank, 1);
// "cell arrange" on m68k
cpu68k_map_set(m68k_read8_map, 0x220000, 0x23ffff, m68k_cell_read8[b0], 1);
cpu68k_map_set(m68k_read16_map, 0x220000, 0x23ffff, m68k_cell_read16[b0], 1);
cpu68k_map_set(m68k_write8_map, 0x220000, 0x23ffff, m68k_cell_write8[b0], 1);
cpu68k_map_set(m68k_write16_map, 0x220000, 0x23ffff, m68k_cell_write16[b0], 1);
cpu68k_map_all_funcs(BASE+0x220000, BASE+0x23ffff,
m68k_cell_read8[b0], m68k_cell_read16[b0],
m68k_cell_write8[b0], m68k_cell_write16[b0], 0);
// "decode format" on s68k
cpu68k_map_set(s68k_read8_map, 0x080000, 0x0bffff, s68k_dec_read8[b0 ^ 1], 1);
cpu68k_map_set(s68k_read16_map, 0x080000, 0x0bffff, s68k_dec_read16[b0 ^ 1], 1);
cpu68k_map_set(s68k_write8_map, 0x080000, 0x0bffff, s68k_dec_write8[b0 ^ 1][m], 1);
cpu68k_map_set(s68k_write16_map, 0x080000, 0x0bffff, s68k_dec_write16[b0 ^ 1][m], 1);
cpu68k_map_all_funcs(0x80000, 0xbffff,
s68k_dec_read8[b0^1], s68k_dec_read16[b0^1],
s68k_dec_write8[b0^1][m], s68k_dec_write16[b0^1][m], 1);
}
#ifdef EMU_F68K
// update fetchmap..
int i;
if (!(r3 & 4))
{
for (i = M68K_FETCHBANK1*2/16; (i<<(24-FAMEC_FETCHBITS)) < 0x240000; i++)
PicoCpuFM68k.Fetch[i] = (unsigned long)Pico_mcd->word_ram2M - 0x200000;
}
else
{
for (i = M68K_FETCHBANK1*2/16; (i<<(24-FAMEC_FETCHBITS)) < 0x220000; i++)
PicoCpuFM68k.Fetch[i] = (unsigned long)Pico_mcd->word_ram1M[r3 & 1] - 0x200000;
for (i = M68K_FETCHBANK1*0x0c/0x100; (i<<(24-FAMEC_FETCHBITS)) < 0x0e0000; i++)
PicoCpuFS68k.Fetch[i] = (unsigned long)Pico_mcd->word_ram1M[(r3&1)^1] - 0x0c0000;
}
#endif
}
void pcd_state_loaded_mem(void)
@ -1102,7 +1219,7 @@ void pcd_state_loaded_mem(void)
Pico_mcd->m.dmna_ret_2m &= 3;
// restore hint vector
*(unsigned short *)(Pico_mcd->bios + 0x72) = Pico_mcd->m.hint_vector;
*(u16 *)(Pico.rom + 0x72) = Pico_mcd->m.hint_vector;
}
#ifdef EMU_M68K
@ -1111,12 +1228,22 @@ static void m68k_mem_setup_cd(void);
PICO_INTERNAL void PicoMemSetupCD(void)
{
if (!Pico_mcd) {
Pico_mcd = plat_mmap(0x05000000, sizeof(mcd_state), 0, 0);
memset(Pico_mcd, 0, sizeof(mcd_state));
}
pcd_base_address = (Pico.romsize > 0x20000 ? 0x400000 : 0x000000);
// setup default main68k map
PicoMemSetup();
// main68k map (BIOS mapped by PicoMemSetup()):
// RAM cart
if (PicoOpt & POPT_EN_MCD_RAMCART) {
// main68k map (BIOS or MSU mapped by PicoMemSetup()):
if (Pico.romsize > 0x20000) {
// MSU cartridge. Fake BIOS detection
cpu68k_map_set(m68k_read8_map, 0x400000, 0x41ffff, PicoReadM68k8_bios, 1);
cpu68k_map_set(m68k_read16_map, 0x400000, 0x41ffff, PicoReadM68k16_bios, 1);
} else {
// RAM cart
cpu68k_map_set(m68k_read8_map, 0x400000, 0x7fffff, PicoReadM68k8_ramc, 1);
cpu68k_map_set(m68k_read16_map, 0x400000, 0x7fffff, PicoReadM68k16_ramc, 1);
cpu68k_map_set(m68k_write8_map, 0x400000, 0x7fffff, PicoWriteM68k8_ramc, 1);
@ -1130,32 +1257,33 @@ PICO_INTERNAL void PicoMemSetupCD(void)
cpu68k_map_set(m68k_write16_map, 0xa10000, 0xa1ffff, PicoWrite16_mcd_io, 1);
// sub68k map
cpu68k_map_set(s68k_read8_map, 0x000000, 0xffffff, s68k_unmapped_read8, 1);
cpu68k_map_set(s68k_read16_map, 0x000000, 0xffffff, s68k_unmapped_read16, 1);
cpu68k_map_set(s68k_write8_map, 0x000000, 0xffffff, s68k_unmapped_write8, 1);
cpu68k_map_set(s68k_write16_map, 0x000000, 0xffffff, s68k_unmapped_write16, 1);
cpu68k_map_set(s68k_read8_map, 0x000000, 0xffffff, s68k_unmapped_read8, 3);
cpu68k_map_set(s68k_read16_map, 0x000000, 0xffffff, s68k_unmapped_read16, 3);
cpu68k_map_set(s68k_write8_map, 0x000000, 0xffffff, s68k_unmapped_write8, 3);
cpu68k_map_set(s68k_write16_map, 0x000000, 0xffffff, s68k_unmapped_write16, 3);
// PRG RAM
cpu68k_map_set(s68k_read8_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 0);
cpu68k_map_set(s68k_read16_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 0);
cpu68k_map_set(s68k_write8_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 0);
cpu68k_map_set(s68k_write16_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 0);
cpu68k_map_set(s68k_write8_map, 0x000000, 0x01ffff, PicoWriteS68k8_prgwp, 1);
cpu68k_map_set(s68k_write16_map, 0x000000, 0x01ffff, PicoWriteS68k16_prgwp, 1);
cpu68k_map_set(s68k_read8_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 2);
cpu68k_map_set(s68k_read16_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 2);
cpu68k_map_set(s68k_write8_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 2);
cpu68k_map_set(s68k_write16_map, 0x000000, 0x07ffff, Pico_mcd->prg_ram, 2);
cpu68k_map_set(s68k_write8_map, 0x000000, 0x01ffff, PicoWriteS68k8_prgwp, 3);
cpu68k_map_set(s68k_write16_map, 0x000000, 0x01ffff, PicoWriteS68k16_prgwp, 3);
// BRAM
cpu68k_map_set(s68k_read8_map, 0xfe0000, 0xfeffff, PicoReadS68k8_bram, 1);
cpu68k_map_set(s68k_read16_map, 0xfe0000, 0xfeffff, PicoReadS68k16_bram, 1);
cpu68k_map_set(s68k_write8_map, 0xfe0000, 0xfeffff, PicoWriteS68k8_bram, 1);
cpu68k_map_set(s68k_write16_map, 0xfe0000, 0xfeffff, PicoWriteS68k16_bram, 1);
cpu68k_map_set(s68k_read8_map, 0xfe0000, 0xfeffff, PicoReadS68k8_bram, 3);
cpu68k_map_set(s68k_read16_map, 0xfe0000, 0xfeffff, PicoReadS68k16_bram, 3);
cpu68k_map_set(s68k_write8_map, 0xfe0000, 0xfeffff, PicoWriteS68k8_bram, 3);
cpu68k_map_set(s68k_write16_map, 0xfe0000, 0xfeffff, PicoWriteS68k16_bram, 3);
// PCM, regs
cpu68k_map_set(s68k_read8_map, 0xff0000, 0xffffff, PicoReadS68k8_pr, 1);
cpu68k_map_set(s68k_read16_map, 0xff0000, 0xffffff, PicoReadS68k16_pr, 1);
cpu68k_map_set(s68k_write8_map, 0xff0000, 0xffffff, PicoWriteS68k8_pr, 1);
cpu68k_map_set(s68k_write16_map, 0xff0000, 0xffffff, PicoWriteS68k16_pr, 1);
cpu68k_map_set(s68k_read8_map, 0xff0000, 0xffffff, PicoReadS68k8_pr, 3);
cpu68k_map_set(s68k_read16_map, 0xff0000, 0xffffff, PicoReadS68k16_pr, 3);
cpu68k_map_set(s68k_write8_map, 0xff0000, 0xffffff, PicoWriteS68k8_pr, 3);
cpu68k_map_set(s68k_write16_map, 0xff0000, 0xffffff, PicoWriteS68k16_pr, 3);
// RAMs
remap_prg_window(2,1);
remap_word_ram(1);
#ifdef EMU_C68K
@ -1173,38 +1301,12 @@ PICO_INTERNAL void PicoMemSetupCD(void)
#endif
#ifdef EMU_F68K
// s68k
PicoCpuFS68k.read_byte = s68k_read8;
PicoCpuFS68k.read_word = s68k_read16;
PicoCpuFS68k.read_long = s68k_read32;
PicoCpuFS68k.write_byte = s68k_write8;
PicoCpuFS68k.write_word = s68k_write16;
PicoCpuFS68k.write_long = s68k_write32;
// setup FAME fetchmap
{
int i;
// M68k
// by default, point everything to fitst 64k of ROM (BIOS)
for (i = 0; i < M68K_FETCHBANK1; i++)
PicoCpuFM68k.Fetch[i] = (unsigned long)Pico.rom - (i<<(24-FAMEC_FETCHBITS));
// now real ROM (BIOS)
for (i = 0; i < M68K_FETCHBANK1 && (i<<(24-FAMEC_FETCHBITS)) < Pico.romsize; i++)
PicoCpuFM68k.Fetch[i] = (unsigned long)Pico.rom;
// .. and RAM
for (i = M68K_FETCHBANK1*14/16; i < M68K_FETCHBANK1; i++)
PicoCpuFM68k.Fetch[i] = (unsigned long)Pico.ram - (i<<(24-FAMEC_FETCHBITS));
// S68k
// PRG RAM is default
for (i = 0; i < M68K_FETCHBANK1; i++)
PicoCpuFS68k.Fetch[i] = (unsigned long)Pico_mcd->prg_ram - (i<<(24-FAMEC_FETCHBITS));
// real PRG RAM
for (i = 0; i < M68K_FETCHBANK1 && (i<<(24-FAMEC_FETCHBITS)) < 0x80000; i++)
PicoCpuFS68k.Fetch[i] = (unsigned long)Pico_mcd->prg_ram;
// WORD RAM 2M area
for (i = M68K_FETCHBANK1*0x08/0x100; i < M68K_FETCHBANK1 && (i<<(24-FAMEC_FETCHBITS)) < 0xc0000; i++)
PicoCpuFS68k.Fetch[i] = (unsigned long)Pico_mcd->word_ram2M - 0x80000;
// remap_word_ram() will setup word ram for both
}
PicoCpuFS68k.read_byte = (void *)s68k_read8;
PicoCpuFS68k.read_word = (void *)s68k_read16;
PicoCpuFS68k.read_long = (void *)s68k_read32;
PicoCpuFS68k.write_byte = (void *)s68k_write8;
PicoCpuFS68k.write_word = (void *)s68k_write16;
PicoCpuFS68k.write_long = (void *)s68k_write32;
#endif
#ifdef EMU_M68K
m68k_mem_setup_cd();

View file

@ -6,6 +6,9 @@
@* See COPYING file in the top-level directory.
@*
#include <pico/arm_features.h>
#include <pico/pico_int_offs.h>
.equiv PCM_STEP_SHIFT, 11
.text
@ -48,7 +51,7 @@
.global PicoWriteS68k16_dec_m2b1
@ externs, just for reference
.extern Pico
.extern Pico_mcd
.extern cdc_host_r
.extern m68k_reg_write8
.extern s68k_reg_read16
@ -57,13 +60,13 @@
.extern s68k_poll_detect
.extern pcd_pcm_write
.extern pcd_pcm_read
.extern PicoCpuCS68k
.extern PicoRead8_io
.extern PicoRead16_io
.extern PicoWrite8_io
.extern PicoWrite16_io
.extern m68k_comm_check
PIC_LDR_INIT()
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ -72,16 +75,16 @@
@ r0=addr[in,out], r1,r2=tmp
.macro cell_map
ands r1, r0, #0x01c000
ldrne pc, [pc, r1, lsr #12]
beq 0f @ most common?
.long 0f
.long 0f
.long 0f
.long 0f
.long 1f
.long 1f
.long 2f
.long 3f
PIC_XB(ne ,r1, lsr #12)
b 0f @ most common?
PIC_BT(0f)
PIC_BT(0f)
PIC_BT(0f)
PIC_BT(0f)
PIC_BT(1f)
PIC_BT(1f)
PIC_BT(2f)
PIC_BT(3f)
1: @ x16 cells
and r1, r0, #0x7e00 @ col
and r2, r0, #0x01fc @ row
@ -127,9 +130,9 @@ PicoReadM68k8_cell1: @ 0x220000 - 0x23ffff, cell arranged
mov r3, #0x0e0000
0:
cell_map
ldr r1, =(Pico+0x22200)
PIC_LDR(r1, r2, Pico_mcd)
add r0, r0, r3
ldr r1, [r1]
ldr r1, [r1] @ Pico.mcd (used everywhere)
eor r0, r0, #1
ldrb r0, [r1, r0]
bx lr
@ -140,31 +143,35 @@ PicoRead8_mcd_io:
cmp r1, #0x2000 @ a120xx?
bne PicoRead8_io
ldr r1, =(Pico+0x22200)
PIC_LDR(r1, r2, Pico_mcd)
and r0, r0, #0x3f
ldr r1, [r1] @ Pico.mcd (used everywhere)
ldr r1, [r1] @ Pico.mcd
cmp r0, #0x0e
ldrlt pc, [pc, r0, lsl #2]
PIC_XB(lt ,r0, lsl #2)
b m_m68k_read8_hi
.long m_m68k_read8_r00
.long m_m68k_read8_r01
.long m_m68k_read8_r02
.long m_m68k_read8_r03
.long m_m68k_read8_r04
.long m_read_null @ unused bits
.long m_m68k_read8_r06
.long m_m68k_read8_r07
.long m_m68k_read8_r08
.long m_m68k_read8_r09
.long m_read_null @ reserved
.long m_read_null
.long m_m68k_read8_r0c
.long m_m68k_read8_r0d
PIC_BT(m_m68k_read8_r00)
PIC_BT(m_m68k_read8_r01)
PIC_BT(m_m68k_read8_r02)
PIC_BT(m_m68k_read8_r03)
PIC_BT(m_m68k_read8_r04)
PIC_BT(m_read_null) @ unused bits
PIC_BT(m_m68k_read8_r06)
PIC_BT(m_m68k_read8_r07)
PIC_BT(m_m68k_read8_r08)
PIC_BT(m_m68k_read8_r09)
PIC_BT(m_read_null) @ reserved
PIC_BT(m_read_null)
PIC_BT(m_m68k_read8_r0c)
PIC_BT(m_m68k_read8_r0d)
m_m68k_read8_r00:
add r1, r1, #0x110000
ldr r0, [r1, #0x30]
ldr r0, [r1, #0x30] @ Pico_mcd->s68k_regs
add r1, r1, #0x002200
ldr r1, [r1, #4] @ Pico_mcd->m.state_flags
and r0, r0, #0x04000000 @ we need irq2 mask state
mov r0, r0, lsr #19
and r1, r1, #0x00000100 @ irq2 pending
orr r0, r0, r1, lsr #8
bx lr
m_m68k_read8_r01:
add r1, r1, #0x110000
@ -177,9 +184,10 @@ m_m68k_read8_r02:
bx lr
m_m68k_read8_r03:
add r1, r1, #0x110000
push {r1, lr}
stmfd sp!, {r1, lr}
bic r0, r0, #1
bl m68k_comm_check
pop {r1, lr}
ldmfd sp!, {r1, lr}
ldrb r0, [r1, #3]
and r0, r0, #0xc7
bx lr
@ -191,6 +199,8 @@ m_m68k_read8_r06:
ldrb r0, [r1, #0x73] @ IRQ vector
bx lr
m_m68k_read8_r07:
PIC_LDR(r1, r2, Pico)
ldr r1, [r1, #OFS_Pico_rom]
ldrb r0, [r1, #0x72]
bx lr
m_m68k_read8_r08:
@ -202,26 +212,23 @@ m_m68k_read8_r09:
mov r0, #0
b cdc_host_r
m_m68k_read8_r0c:
add r1, r1, #0x110000
add r1, r1, #0x002200
ldr r0, [r1, #0x14] @ Pico_mcd->m.timer_stopwatch
mov r0, r0, lsr #24
mov r1, #0
bl pcd_stopwatch_read
mov r0, r0, lsr #8
bx lr
m_m68k_read8_r0d:
add r1, r1, #0x110000
add r1, r1, #0x002200
ldr r0, [r1, #0x14]
mov r0, r0, lsr #16
bx lr
mov r1, #0
b pcd_stopwatch_read
m_m68k_read8_hi:
cmp r0, #0x30
add r1, r1, #0x110000
movge r0, #0
bxge lr
add r1, r0
push {r1, lr}
add r1, r1, r0
stmfd sp!, {r1, lr}
bic r0, r0, #1
bl m68k_comm_check
pop {r1, lr}
ldmfd sp!, {r1, lr}
ldrb r0, [r1]
bx lr
@ -237,9 +244,9 @@ PicoReadM68k16_cell1: @ 0x220000 - 0x23ffff, cell arranged
mov r3, #0x0e0000
0:
cell_map
ldr r1, =(Pico+0x22200)
PIC_LDR(r1, r2, Pico_mcd)
add r0, r0, r3
ldr r1, [r1]
ldr r1, [r1] @ Pico.mcd
bic r0, r0, #1
ldrh r0, [r1, r0]
bx lr
@ -251,32 +258,35 @@ PicoRead16_mcd_io:
bne PicoRead16_io
m_m68k_read16_m68k_regs:
ldr r1, =(Pico+0x22200)
PIC_LDR(r1, r2, Pico_mcd)
and r0, r0, #0x3e
ldr r1, [r1] @ Pico.mcd (used everywhere)
ldr r1, [r1] @ Pico.mcd
cmp r0, #0x0e
ldrlt pc, [pc, r0, lsl #1]
PIC_XB(lt ,r0, lsl #1)
b m_m68k_read16_hi
.long m_m68k_read16_r00
.long m_m68k_read16_r02
.long m_m68k_read16_r04
.long m_m68k_read16_r06
.long m_m68k_read16_r08
.long m_read_null @ reserved
.long m_m68k_read16_r0c
PIC_BT(m_m68k_read16_r00)
PIC_BT(m_m68k_read16_r02)
PIC_BT(m_m68k_read16_r04)
PIC_BT(m_m68k_read16_r06)
PIC_BT(m_m68k_read16_r08)
PIC_BT(m_read_null) @ reserved
PIC_BT(m_m68k_read16_r0c)
m_m68k_read16_r00:
add r1, r1, #0x110000
ldr r0, [r1, #0x30]
add r1, r1, #0x002200
ldrb r1, [r1, #2] @ Pico_mcd->m.busreq
ldrb r2, [r1, #2] @ Pico_mcd->m.busreq
ldr r1, [r1, #4]
and r0, r0, #0x04000000 @ we need irq2 mask state
orr r0, r1, r0, lsr #11
orr r0, r2, r0, lsr #11
and r1, r1, #0x00000100 @ irq2 pending
orr r0, r1, r0
bx lr
m_m68k_read16_r02:
add r1, r1, #0x110000
push {r1, lr}
stmfd sp!, {r1, lr}
bl m68k_comm_check
pop {r1, lr}
ldmfd sp!, {r1, lr}
ldrb r2, [r1, #3]
ldrb r0, [r1, #2]
and r2, r2, #0xc7
@ -288,17 +298,16 @@ m_m68k_read16_r04:
mov r0, r0, lsl #8
bx lr
m_m68k_read16_r06:
PIC_LDR(r1, r2, Pico)
ldr r1, [r1, #OFS_Pico_rom]
ldrh r0, [r1, #0x72] @ IRQ vector
bx lr
m_m68k_read16_r08:
mov r0, #0
b cdc_host_r
m_m68k_read16_r0c:
add r1, r1, #0x110000
add r1, r1, #0x002200
ldr r0, [r1, #0x14]
mov r0, r0, lsr #16
bx lr
mov r1, #0
b pcd_stopwatch_read
m_m68k_read16_hi:
cmp r0, #0x30
add r1, r1, #0x110000
@ -306,9 +315,9 @@ m_m68k_read16_hi:
bxge lr
add r1, r0, r1
push {r1, lr}
stmfd sp!, {r1, lr}
bl m68k_comm_check
pop {r0, lr}
ldmfd sp!, {r0, lr}
ldrh r0, [r0]
mov r1, r0, lsr #8
and r0, r0, #0xff
@ -328,8 +337,9 @@ PicoWriteM68k8_cell1: @ 0x220000 - 0x23ffff, cell arranged
0:
mov r3, r1
cell_map
ldr r2, =(Pico+0x22200)
PIC_LDR(r2, r1, Pico_mcd)
add r0, r0, r12
ldr r2, [r2] @ Pico.mcd
ldr r2, [r2]
eor r0, r0, #1
strb r3, [r2, r0]
@ -355,9 +365,9 @@ PicoWriteM68k16_cell1: @ 0x220000 - 0x23ffff, cell arranged
0:
mov r3, r1
cell_map
ldr r1, =(Pico+0x22200)
PIC_LDR(r1, r2, Pico_mcd)
add r0, r0, r12
ldr r1, [r1]
ldr r1, [r1] @ Pico.mcd
bic r0, r0, #1
strh r3, [r1, r0]
bx lr
@ -374,10 +384,10 @@ m_m68k_write16_regs:
beq m_m68k_write16_regs_spec
and r3, r1, #0xff
add r2, r0, #1
stmfd sp!,{r2,r3,lr}
stmfd sp!,{r2,r3,r12,lr}
mov r1, r1, lsr #8
bl m68k_reg_write8
ldmfd sp!,{r0,r1,lr}
ldmfd sp!,{r0,r1,r12,lr}
b m68k_reg_write8
m_m68k_write16_regs_spec: @ special case
@ -397,9 +407,9 @@ PicoReadS68k8_dec0: @ 0x080000 - 0x0bffff
PicoReadS68k8_dec1:
mov r3, #0x0a0000 @ + ^ / 2
0:
ldr r2, =(Pico+0x22200)
PIC_LDR(r2, r1, Pico_mcd)
eor r0, r0, #2
ldr r2, [r2]
ldr r2, [r2] @ Pico.mcd
movs r0, r0, lsr #1 @ +4-6 <<16
add r2, r2, r3 @ map to our address
ldrb r0, [r2, r0]
@ -429,8 +439,8 @@ m_s68k_read8_regs:
bx lr
m_s68k_read8_comm:
ldr r1, =(Pico+0x22200)
ldr r1, [r1]
PIC_LDR(r1, r2, Pico_mcd)
ldr r1, [r1] @ Pico.mcd
add r1, r1, #0x110000
ldrb r1, [r1, r0]
bic r0, r0, #1
@ -442,9 +452,9 @@ m_s68k_read8_pcm:
bne m_read_null
@ must not trash r3 and r12
ldr r1, =(Pico+0x22200)
PIC_LDR(r1, r2, Pico_mcd)
bic r0, r0, #0xff0000
ldr r1, [r1]
ldr r1, [r1] @ Pico.mcd
mov r2, #0x110000
orr r2, r2, #0x002200
cmp r0, #0x2000
@ -477,9 +487,9 @@ PicoReadS68k16_dec0: @ 0x080000 - 0x0bffff
PicoReadS68k16_dec1:
mov r3, #0x0a0000 @ + ^ / 2
0:
ldr r2, =(Pico+0x22200)
PIC_LDR(r2, r1, Pico_mcd)
eor r0, r0, #2
ldr r2, [r2]
ldr r2, [r2] @ Pico.mcd
mov r0, r0, lsr #1 @ +4-6 <<16
add r2, r2, r3 @ map to our address
ldrb r0, [r2, r0]
@ -503,14 +513,13 @@ m_s68k_read16_regs:
mov r0, #1
b cdc_host_r
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.macro m_s68k_write8_2M_decode
ldr r2, =(Pico+0x22200)
PIC_LDR(r2, ip, Pico_mcd)
eor r0, r0, #2
ldr r2, [r2] @ Pico.rom
ldr r2, [r2] @ Pico.mcd
movs r0, r0, lsr #1 @ +4-6 <<16
add r2, r2, r3 @ map to our address
.endm
@ -592,9 +601,9 @@ m_s68k_write8_pcm:
bxlt lr
m_s68k_write8_pcm_ram:
ldr r3, =(Pico+0x22200)
PIC_LDR(r3, r2, Pico_mcd)
bic r0, r0, #0x00e000
ldr r3, [r3]
ldr r3, [r3] @ Pico.mcd
mov r0, r0, lsr #1
add r2, r3, #0x110000
add r2, r2, #0x002200
@ -606,14 +615,13 @@ m_s68k_write8_pcm_ram:
strb r1, [r3, r0]
bx lr
@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
.macro m_s68k_write16_2M_decode
ldr r2, =(Pico+0x22200)
PIC_LDR(r2, ip, Pico_mcd)
eor r0, r0, #2
ldr r2, [r2]
ldr r2, [r2] @ Pico.mcd
mov r0, r0, lsr #1 @ +4-6 <<16
add r2, r2, r3 @ map to our address
.endm
@ -692,13 +700,110 @@ m_s68k_write16_regs:
bne s68k_reg_write16
m_s68k_write16_regs_spec: @ special case
ldr r2, =(Pico+0x22200)
PIC_LDR(r2, r0, Pico_mcd)
mov r0, #0x110000
ldr r2, [r2]
ldr r2, [r2] @ Pico.mcd
add r0, r0, #0x00000f
strb r1, [r2, r0] @ if (a == 0xe) s68k_regs[0xf] = d;
bx lr
.global s68k_read8
.global s68k_read16
.global s68k_read32
.global s68k_write8
.global s68k_write16
.global s68k_write32
s68k_read8:
PIC_LDR(r3, r2, s68k_read8_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
eor r2, r0, #1
movs r3, r3, lsl #1
ldrccb r0, [r3, r2]
bxcc lr
bx r3
s68k_read16:
PIC_LDR(r3, r2, s68k_read16_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
bic r0, r0, #1
movs r3, r3, lsl #1
ldrcch r0, [r3, r0]
bxcc lr
bx r3
s68k_read32:
PIC_LDR(r3, r2, s68k_read16_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
bic r0, r0, #1
movs r3, r3, lsl #1
ldrcch r1, [r3, r0]!
ldrcch r0, [r3, #2]
orrcc r0, r0, r1, lsl #16
bxcc lr
stmfd sp!, {r0, r3, r4, lr}
mov lr, pc
bx r3
ldmfd sp!, {r1, r3}
str r0, [sp]
add r0, r1, #2
mov lr, pc
bx r3
ldmfd sp!, {r1, lr}
mov r0, r0, lsl #16
mov r1, r1, lsl #16
orr r0, r1, r0, lsr #16
bx lr
s68k_write8:
PIC_LDR(r3, r2, s68k_write8_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
eor r2, r0, #1
movs r3, r3, lsl #1
strccb r1, [r3, r2]
bxcc lr
bx r3
s68k_write16:
PIC_LDR(r3, r2, s68k_write16_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
bic r0, r0, #1
movs r3, r3, lsl #1
strcch r1, [r3, r0]
bxcc lr
bx r3
s68k_write32:
PIC_LDR(r3, r2, s68k_write16_map)
bic r0, r0, #0xff000000
mov r2, r0, lsr #16
ldr r3, [r3, r2, lsl #2]
bic r0, r0, #1
movs r3, r3, lsl #1
movcc r2, r1, lsr #16
strcch r2, [r3, r0]!
strcch r1, [r3, #2]
bxcc lr
stmfd sp!, {r0, r1, r3, lr}
mov r1, r1, lsr #16
mov lr, pc
bx r3
ldmfd sp!, {r0, r1, r3, lr}
add r0, r0, #2
bx r3
.pool
@ vim:filetype=armasm

View file

@ -88,29 +88,30 @@ void pcd_pcm_sync(unsigned int to)
}
addr = ch->addr;
inc = *(unsigned short *)&ch->regs[2];
mul_l = ((int)ch->regs[0] * (ch->regs[1] & 0xf)) >> (5+1);
mul_r = ((int)ch->regs[0] * (ch->regs[1] >> 4)) >> (5+1);
inc = ch->regs[2] + (ch->regs[3]<<8);
mul_l = (int)ch->regs[0] * (ch->regs[1] & 0xf);
mul_r = (int)ch->regs[0] * (ch->regs[1] >> 4);
for (s = 0; s < steps; s++, addr = (addr + inc) & 0x7FFFFFF)
for (s = 0; s < steps; s++)
{
smp = Pico_mcd->pcm_ram[addr >> PCM_STEP_SHIFT];
// test for loop signal
if (smp == 0xff)
{
addr = *(unsigned short *)&ch->regs[4]; // loop_addr
addr = ch->regs[4] + (ch->regs[5]<<8); // loop_addr
smp = Pico_mcd->pcm_ram[addr];
addr <<= PCM_STEP_SHIFT;
if (smp == 0xff)
break;
}
} else
addr = (addr + inc) & 0x07FFFFFF;
if (smp & 0x80)
smp = -(smp & 0x7f);
out[s*2 ] += smp * mul_l; // max 128 * 119 = 15232
out[s*2+1] += smp * mul_r;
out[s*2 ] += (smp * mul_l) >> 5; // max 127 * 255 * 15 / 32 = 15180
out[s*2+1] += (smp * mul_r) >> 5;
}
ch->addr = addr;
}
@ -120,14 +121,14 @@ end:
Pico_mcd->pcm_mixpos += steps;
}
void pcd_pcm_update(int *buf32, int length, int stereo)
void pcd_pcm_update(s32 *buf32, int length, int stereo)
{
int step, *pcm;
int p = 0;
pcd_pcm_sync(SekCyclesDoneS68k());
if (!Pico_mcd->pcm_mixbuf_dirty || !(PicoOpt & POPT_EN_MCD_PCM))
if (!Pico_mcd->pcm_mixbuf_dirty || !(PicoIn.opt & POPT_EN_MCD_PCM) || !buf32)
goto out;
step = (Pico_mcd->pcm_mixpos << 16) / length;

View file

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

View file

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

View file

@ -8,7 +8,6 @@
#include "pico_int.h"
typedef unsigned char u8;
static unsigned int pppc, ops=0;
extern unsigned int lastread_a, lastread_d[16], lastwrite_cyc_d[16], lastwrite_mus_d[16];
@ -30,6 +29,7 @@ static struct Cyclone *currentC68k = NULL;
#define other_is_stopped() (currentC68k->state_flags&1)
#define other_is_tracing() ((currentC68k->state_flags&2)?1:0)
#elif defined(EMU_F68K)
static struct M68K_CONTEXT *g_m68kcontext;
#define other_set_sub(s) g_m68kcontext=(s)?&PicoCpuFS68k:&PicoCpuFM68k;
#define other_get_sr() g_m68kcontext->sr
#define other_dar(i) ((unsigned int*)g_m68kcontext->dreg)[i]
@ -49,7 +49,7 @@ static int otherRun(void)
CycloneRun(currentC68k);
return 1-currentC68k->cycles;
#elif defined(EMU_F68K)
return fm68k_emulate(1, 0);
return fm68k_emulate(g_m68kcontext, 1, 0);
#endif
}

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
/*
* tile renderer
* (C) notaz, 2006-2008
* (C) irixxxx, 2020-2023
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
@ -11,6 +12,9 @@
#define START_ROW 0 // which row of tiles to start rendering at?
#define END_ROW 28 // ..end
#define VSRAM 0 // 2-cell vscroll (broken for line based hscroll)
#define INTERLACE 0 // interlace mode 2
#define TILE_ROWS END_ROW-START_ROW
// note: this is not implemented in ARM asm
@ -20,33 +24,37 @@
#define LINE_WIDTH 328
#endif
static unsigned char PicoDraw2FB_[(8+320) * (8+240+8)];
unsigned char *PicoDraw2FB = PicoDraw2FB_;
static unsigned char PicoDraw2FB_[LINE_WIDTH * (8+240+8) + 8];
static int HighCache2A[41*(TILE_ROWS+1)+1+1]; // caches for high layers
static int HighCache2B[41*(TILE_ROWS+1)+1+1];
static u32 HighCache2A[2*41*(TILE_ROWS+1)+1+1]; // caches for high layers
static u32 HighCache2B[2*41*(TILE_ROWS+1)+1+1];
unsigned short *PicoCramHigh=Pico.cram; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now)
void (*PicoPrepareCram)()=0; // prepares PicoCramHigh for renderer to use
unsigned short *PicoCramHigh=PicoMem.cram; // pointer to CRAM buff (0x40 shorts), converted to native device color (works only with 16bit for now)
void (*PicoPrepareCram)(void) = NULL; // prepares PicoCramHigh for renderer to use
// stuff available in asm:
#ifdef _ASM_DRAW_C
void BackFillFull(int reg7);
void DrawLayerFull(int plane, int *hcache, int planestart, int planeend);
void DrawTilesFromCacheF(int *hc);
void DrawWindowFull(int start, int end, int prio);
void DrawSpriteFull(unsigned int *sprite);
void BackFillFull(void *dst, int reg7, int lwidth);
void DrawLayerFull(int plane, u32 *hcache, int planestart, int planeend,
struct PicoEState *est);
void DrawTilesFromCacheF(u32 *hc, struct PicoEState *est);
void DrawWindowFull(int start, int end, int prio, struct PicoEState *est);
void DrawSpriteFull(unsigned int *sprite, struct PicoEState *est);
#else
static int TileXnormYnorm(unsigned char *pd,int addr,unsigned char pal)
static int TileXnormYnorm(unsigned char *pd,int addr,unsigned char pal, struct PicoEState *est)
{
unsigned int pack=0; unsigned int t=0, blank = 1;
int i;
unsigned short *vram = est->PicoMem_vram;
int i, inc=2;
for(i=8; i; i--, addr+=2, pd += LINE_WIDTH) {
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE) inc = 4;
#endif
for(i=8; i; i--, addr+=inc, pd += est->Draw2Width) {
pack=*(u32 *)(vram+addr); // Get 8 pixels
if(!pack) continue;
t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal);
@ -63,13 +71,17 @@ static int TileXnormYnorm(unsigned char *pd,int addr,unsigned char pal)
return blank; // Tile blank?
}
static int TileXflipYnorm(unsigned char *pd,int addr,unsigned char pal)
static int TileXflipYnorm(unsigned char *pd,int addr,unsigned char pal, struct PicoEState *est)
{
unsigned int pack=0; unsigned int t=0, blank = 1;
int i;
unsigned short *vram = est->PicoMem_vram;
int i, inc=2;
for(i=8; i; i--, addr+=2, pd += LINE_WIDTH) {
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE) inc = 4;
#endif
for(i=8; i; i--, addr+=inc, pd += est->Draw2Width) {
pack=*(u32 *)(vram+addr); // Get 8 pixels
if(!pack) continue;
t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal);
@ -85,14 +97,18 @@ static int TileXflipYnorm(unsigned char *pd,int addr,unsigned char pal)
return blank; // Tile blank?
}
static int TileXnormYflip(unsigned char *pd,int addr,unsigned char pal)
static int TileXnormYflip(unsigned char *pd,int addr,unsigned char pal, struct PicoEState *est)
{
unsigned int pack=0; unsigned int t=0, blank = 1;
int i;
unsigned short *vram = est->PicoMem_vram;
int i, inc=2;
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE) inc = 4, addr += 16;
#endif
addr+=14;
for(i=8; i; i--, addr-=2, pd += LINE_WIDTH) {
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
for(i=8; i; i--, addr-=inc, pd += est->Draw2Width) {
pack=*(u32 *)(vram+addr); // Get 8 pixels
if(!pack) continue;
t=pack&0x0000f000; if (t) pd[0]=(unsigned char)((t>>12)|pal);
@ -109,14 +125,18 @@ static int TileXnormYflip(unsigned char *pd,int addr,unsigned char pal)
return blank; // Tile blank?
}
static int TileXflipYflip(unsigned char *pd,int addr,unsigned char pal)
static int TileXflipYflip(unsigned char *pd,int addr,unsigned char pal, struct PicoEState *est)
{
unsigned int pack=0; unsigned int t=0, blank = 1;
int i;
unsigned short *vram = est->PicoMem_vram;
int i, inc=2;
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE) inc = 4, addr += 16;
#endif
addr+=14;
for(i=8; i; i--, addr-=2, pd += LINE_WIDTH) {
pack=*(unsigned int *)(Pico.vram+addr); // Get 8 pixels
for(i=8; i; i--, addr-=inc, pd += est->Draw2Width) {
pack=*(u32 *)(vram+addr); // Get 8 pixels
if(!pack) continue;
t=pack&0x000f0000; if (t) pd[0]=(unsigned char)((t>>16)|pal);
@ -134,11 +154,12 @@ static int TileXflipYflip(unsigned char *pd,int addr,unsigned char pal)
// start: (tile_start<<16)|row_start, end: [same]
static void DrawWindowFull(int start, int end, int prio)
static void DrawWindowFull(int start, int end, int prio, struct PicoEState *est)
{
struct PicoVideo *pvid=&Pico.video;
struct PicoVideo *pvid=&est->Pico->video;
int nametab, nametab_step, trow, tilex, blank=-1, code;
unsigned char *scrpos = PicoDraw2FB;
unsigned char *scrpos = est->Draw2FB;
int scrstart = est->Draw2Start;
int tile_start, tile_end; // in cells
// parse ranges
@ -148,7 +169,7 @@ static void DrawWindowFull(int start, int end, int prio)
end = end<<16>>16;
// Find name table line:
if (pvid->reg[12]&1)
if (!(est->rendstatus & PDRAW_32_COLS))
{
nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode
nametab_step = 1<<6;
@ -157,15 +178,17 @@ static void DrawWindowFull(int start, int end, int prio)
{
nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode
nametab_step = 1<<5;
if (est->rendstatus & PDRAW_BORDER_32)
scrpos += 32;
}
nametab += nametab_step*start;
nametab += nametab_step*(start-scrstart);
// check priority
code=Pico.vram[nametab+tile_start];
code=est->PicoMem_vram[nametab+tile_start];
if ((code>>15) != prio) return; // hack: just assume that whole window uses same priority
scrpos+=8*LINE_WIDTH+8;
scrpos+=8*LINE_WIDTH*(start-START_ROW);
scrpos+=8*est->Draw2Width+8;
scrpos+=8*est->Draw2Width*(start-scrstart);
// do a window until we reach planestart row
for(trow = start; trow < end; trow++, nametab+=nametab_step) { // current tile row
@ -175,36 +198,43 @@ static void DrawWindowFull(int start, int end, int prio)
// unsigned short *pal=NULL;
unsigned char pal;
code=Pico.vram[nametab+tilex];
code=est->PicoMem_vram[nametab+tilex];
if (code==blank) continue;
// Get tile address/2:
addr=(code&0x7ff)<<4;
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE)
addr=(code&0x3ff)<<5;
else
#endif
addr=(code&0x7ff)<<4;
// pal=PicoCramHigh+((code>>9)&0x30);
pal=(unsigned char)((code>>9)&0x30);
switch((code>>11)&3) {
case 0: zero=TileXnormYnorm(scrpos+(tilex<<3),addr,pal); break;
case 1: zero=TileXflipYnorm(scrpos+(tilex<<3),addr,pal); break;
case 2: zero=TileXnormYflip(scrpos+(tilex<<3),addr,pal); break;
case 3: zero=TileXflipYflip(scrpos+(tilex<<3),addr,pal); break;
case 0: zero=TileXnormYnorm(scrpos+(tilex<<3),addr,pal,est); break;
case 1: zero=TileXflipYnorm(scrpos+(tilex<<3),addr,pal,est); break;
case 2: zero=TileXnormYflip(scrpos+(tilex<<3),addr,pal,est); break;
case 3: zero=TileXflipYflip(scrpos+(tilex<<3),addr,pal,est); break;
}
if(zero) blank=code; // We know this tile is blank now
}
scrpos += LINE_WIDTH*8;
scrpos += est->Draw2Width*8;
}
}
static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend)
static void DrawLayerFull(int plane, u32 *hcache, int planestart, int planeend,
struct PicoEState *est)
{
struct PicoVideo *pvid=&Pico.video;
static char shift[4]={5,6,6,7}; // 32,64 or 128 sized tilemaps
struct PicoVideo *pvid=&est->Pico->video;
static char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps
int width, height, ymask, htab;
int nametab, hscroll=0, vscroll, cells;
unsigned char *scrpos;
int scrstart = est->Draw2Start;
int blank=-1, xmask, nametab_row, trow;
// parse ranges
@ -221,7 +251,7 @@ static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend)
if(!(pvid->reg[11]&3)) { // full screen scroll
// Get horizontal scroll value
hscroll=Pico.vram[htab&0x7fff];
hscroll=est->PicoMem_vram[htab&0x7fff];
htab = 0; // this marks that we don't have to update scroll value
}
@ -238,104 +268,138 @@ static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend)
if (plane==0) nametab=(pvid->reg[2]&0x38)<< 9; // A
else nametab=(pvid->reg[4]&0x07)<<12; // B
scrpos = PicoDraw2FB;
scrpos+=8*LINE_WIDTH*(planestart-START_ROW);
// Get vertical scroll value:
vscroll=Pico.vsram[plane]&0x1ff;
scrpos+=(8-(vscroll&7))*LINE_WIDTH;
if(vscroll&7) planeend++; // we have vertically clipped tiles due to vscroll, so we need 1 more row
*hcache++ = 8-(vscroll&7); // push y-offset to tilecache
scrpos = est->Draw2FB;
if ((~est->rendstatus & (PDRAW_BORDER_32|PDRAW_32_COLS)) == 0)
scrpos += 32;
scrpos+=8*est->Draw2Width*(planestart-scrstart);
if((pvid->reg[11]&4)||(PicoMem.vsram[plane]&7))
planeend++; // we (may) have vertically clipped tiles due to vscroll, so we need 1 more row
for(trow = planestart; trow < planeend; trow++) { // current tile row
int cellc=cells,tilex,dx;
int cellc=cells,tilex,dx,vsidx=0;
// Get vertical scroll value:
vscroll=PicoMem.vsram[plane];//&0x1ff;
#if VSRAM
if ((est->rendstatus & PDRAW_32_COLS) && (pvid->reg[11]&4)) // H32 + 2-cell mode
vscroll=PicoMem.vsram[plane+0x20];//&0x1ff;
#endif
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE)
vscroll >>= 1;
#endif
nametab_row = nametab + (((trow+(vscroll>>3))&ymask)<<shift[width]); // pointer to nametable entries for this row
// Find the tile row in the name table
//ts.line=(vscroll+Scanline)&ymask;
//ts.nametab+=(ts.line>>3)<<shift[width];
nametab_row = nametab + (((trow+(vscroll>>3))&ymask)<<shift[width]); // pointer to nametable entries for this row
// update hscroll if needed
if(htab) {
int htaddr=htab+(trow<<4);
if(trow) htaddr-=(vscroll&7)<<1;
hscroll=Pico.vram[htaddr&0x7fff];
hscroll=est->PicoMem_vram[htaddr&0x7fff];
}
// Draw tiles across screen:
tilex=(-hscroll)>>3;
dx=((hscroll-1)&7)+1;
if(dx != 8) cellc++; // have hscroll, do more cells
if(dx != 8) cellc++, vsidx--; // have hscroll, do more cells
for (; cellc; dx+=8,tilex++,cellc--)
{
int code=0,addr=0,zero=0;
int code=0,addr=0,zero=0,scroff;
// unsigned short *pal=NULL;
unsigned char pal;
code=Pico.vram[nametab_row+(tilex&xmask)];
#if VSRAM
if ((pvid->reg[11]&4) && !(vsidx&1)) { // 2-cell mode
vscroll=PicoMem.vsram[vsidx+plane];//&0x1ff;
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE)
vscroll >>= 1;
#endif
nametab_row = nametab + (((trow+(vscroll>>3))&ymask)<<shift[width]); // pointer to nametable entries for this row
}
#endif
vsidx++;
code=est->PicoMem_vram[nametab_row+(tilex&xmask)];
if (code==blank) continue;
if (code>>15) { // high priority tile
*hcache++ = code|(dx<<16)|(trow<<27); // cache it
*hcache++ = 8-(vscroll&7); // push y-offset to tilecache
continue;
}
// Get tile address/2:
addr=(code&0x7ff)<<4;
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE)
addr=(code&0x3ff)<<5;
else
#endif
addr=(code&0x7ff)<<4;
// pal=PicoCramHigh+((code>>9)&0x30);
pal=(unsigned char)((code>>9)&0x30);
scroff=(8-(vscroll&7))*est->Draw2Width;
switch((code>>11)&3) {
case 0: zero=TileXnormYnorm(scrpos+dx,addr,pal); break;
case 1: zero=TileXflipYnorm(scrpos+dx,addr,pal); break;
case 2: zero=TileXnormYflip(scrpos+dx,addr,pal); break;
case 3: zero=TileXflipYflip(scrpos+dx,addr,pal); break;
case 0: zero=TileXnormYnorm(scrpos+scroff+dx,addr,pal,est); break;
case 1: zero=TileXflipYnorm(scrpos+scroff+dx,addr,pal,est); break;
case 2: zero=TileXnormYflip(scrpos+scroff+dx,addr,pal,est); break;
case 3: zero=TileXflipYflip(scrpos+scroff+dx,addr,pal,est); break;
}
if(zero) blank=code; // We know this tile is blank now
}
scrpos += LINE_WIDTH*8;
scrpos += est->Draw2Width*8;
}
*hcache = 0; // terminate cache
}
static void DrawTilesFromCacheF(int *hc)
static void DrawTilesFromCacheF(u32 *hc, struct PicoEState *est)
{
int code, addr, zero = 0;
u32 code;
int addr, zero = 0, vscroll;
unsigned int prevy=0xFFFFFFFF;
// unsigned short *pal;
unsigned char pal;
short blank=-1; // The tile we know is blank
unsigned char *scrpos = PicoDraw2FB, *pd = 0;
unsigned char *scrpos = est->Draw2FB, *pd = 0;
int scrstart = est->Draw2Start;
// *hcache++ = code|(dx<<16)|(trow<<27); // cache it
scrpos+=(*hc++)*LINE_WIDTH - START_ROW*LINE_WIDTH*8;
if ((~est->rendstatus & (PDRAW_BORDER_32|PDRAW_32_COLS)) == 0)
scrpos += 32;
while((code=*hc++)) {
vscroll=(*hc++ - START_ROW*8)*est->Draw2Width;
if((short)code == blank) continue;
// y pos
if(((unsigned)code>>27) != prevy) {
prevy = (unsigned)code>>27;
pd = scrpos + prevy*LINE_WIDTH*8;
pd = scrpos + (prevy-scrstart)*est->Draw2Width*8;
}
// Get tile address/2:
addr=(code&0x7ff)<<4;
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE)
addr=(code&0x3ff)<<5;
else
#endif
addr=(code&0x7ff)<<4;
// pal=PicoCramHigh+((code>>9)&0x30);
pal=(unsigned char)((code>>9)&0x30);
switch((code>>11)&3) {
case 0: zero=TileXnormYnorm(pd+((code>>16)&0x1ff),addr,pal); break;
case 1: zero=TileXflipYnorm(pd+((code>>16)&0x1ff),addr,pal); break;
case 2: zero=TileXnormYflip(pd+((code>>16)&0x1ff),addr,pal); break;
case 3: zero=TileXflipYflip(pd+((code>>16)&0x1ff),addr,pal); break;
case 0: zero=TileXnormYnorm(pd+vscroll+((code>>16)&0x1ff),addr,pal,est); break;
case 1: zero=TileXflipYnorm(pd+vscroll+((code>>16)&0x1ff),addr,pal,est); break;
case 2: zero=TileXnormYflip(pd+vscroll+((code>>16)&0x1ff),addr,pal,est); break;
case 3: zero=TileXflipYflip(pd+vscroll+((code>>16)&0x1ff),addr,pal,est); break;
}
if(zero) blank=(short)code;
@ -344,18 +408,24 @@ static void DrawTilesFromCacheF(int *hc)
// sx and sy are coords of virtual screen with 8pix borders on top and on left
static void DrawSpriteFull(unsigned int *sprite)
static void DrawSpriteFull(u32 *sprite, struct PicoEState *est)
{
int width=0,height=0;
// unsigned short *pal=NULL;
unsigned char pal;
int tile,code,tdeltax,tdeltay;
unsigned char *scrpos;
int scrstart = est->Draw2Start;
int sx, sy;
sy=sprite[0];
height=sy>>24;
sy=(sy&0x1ff)-0x78; // Y
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE)
sy = ((sy>>1)&0x1ff)-0x78;
else
#endif
sy=(sy&0x1ff)-0x78; // Y
width=(height>>2)&3; height&=3;
width++; height++; // Width and height in tiles
@ -365,22 +435,25 @@ static void DrawSpriteFull(unsigned int *sprite)
tile=code&0x7ff; // Tile number
tdeltax=height; // Delta to increase tile by going right
tdeltay=1; // Delta to increase tile by going down
if (code&0x0800) { tdeltax=-tdeltax; tile+=height*(width-1); } // Flip X
if (code&0x1000) { tdeltay=-tdeltay; tile+=height-1; } // Flip Y
if (code&0x1000) { tile+=tdeltax-1; tdeltay=-tdeltay; } // Flip Y
if (code&0x0800) { tile+=tdeltax*(width-1); tdeltax=-tdeltax; } // Flip X
//delta<<=4; // Delta of address
// pal=PicoCramHigh+((code>>9)&0x30); // Get palette pointer
pal=(unsigned char)((code>>9)&0x30);
// goto first vertically visible tile
while(sy <= START_ROW*8) { sy+=8; tile+=tdeltay; height--; }
sy -= scrstart*8;
while(sy <= 0) { sy+=8; tile+=tdeltay; height--; }
scrpos = PicoDraw2FB;
scrpos+=(sy-START_ROW*8)*LINE_WIDTH;
scrpos = est->Draw2FB;
if ((~est->rendstatus & (PDRAW_BORDER_32|PDRAW_32_COLS)) == 0)
scrpos += 32;
scrpos+=sy*est->Draw2Width;
for (; height > 0; height--, sy+=8, tile+=tdeltay)
{
int w = width, x=sx, t=tile;
int w = width, x=sx, t=tile, s;
if(sy >= END_ROW*8+8) return; // offscreen
@ -390,44 +463,59 @@ static void DrawSpriteFull(unsigned int *sprite)
if(x>=328) break; // Offscreen
t&=0x7fff; // Clip tile address
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE)
s=5;
else
#endif
s=4;
switch((code>>11)&3) {
case 0: TileXnormYnorm(scrpos+x,t<<4,pal); break;
case 1: TileXflipYnorm(scrpos+x,t<<4,pal); break;
case 2: TileXnormYflip(scrpos+x,t<<4,pal); break;
case 3: TileXflipYflip(scrpos+x,t<<4,pal); break;
case 0: TileXnormYnorm(scrpos+x,t<<s,pal,est); break;
case 1: TileXflipYnorm(scrpos+x,t<<s,pal,est); break;
case 2: TileXnormYflip(scrpos+x,t<<s,pal,est); break;
case 3: TileXflipYflip(scrpos+x,t<<s,pal,est); break;
}
}
scrpos+=8*LINE_WIDTH;
scrpos+=8*est->Draw2Width;
}
}
#endif
static void DrawAllSpritesFull(int prio, int maxwidth)
static void DrawAllSpritesFull(int prio, int maxwidth, struct PicoEState *est)
{
struct PicoVideo *pvid=&Pico.video;
struct PicoVideo *pvid=&est->Pico->video;
int table=0,maskrange=0;
int i,u,link=0;
unsigned int *sprites[80]; // Sprites
u32 *sprites[80]; // Sprites
int y_min=START_ROW*8, y_max=END_ROW*8; // for a simple sprite masking
int max_sprites = !(est->rendstatus & PDRAW_32_COLS) ? 80 : 64;
if (est->rendstatus & PDRAW_30_ROWS)
y_min += 8, y_max += 8;
table=pvid->reg[5]&0x7f;
if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode
if (!(est->rendstatus & PDRAW_32_COLS)) table&=0x7e; // Lowest bit 0 in 40-cell mode
table<<=8; // Get sprite table address/2
for (i=u=0; u < 80; u++)
for (i = u = 0; u < max_sprites && link < max_sprites; u++)
{
unsigned int *sprite=NULL;
u32 *sprite=NULL;
int code, code2, sx, sy, height;
sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite
sprite=(u32 *)(est->PicoMem_vram+((table+(link<<2))&0x7ffc)); // Find sprite
// get sprite info
code = sprite[0];
// check if it is not hidden vertically
sy = (code&0x1ff)-0x80;
#if INTERLACE
if (est->rendstatus & PDRAW_INTERLACE)
sy = ((code>>1)&0x1ff)-0x80;
else
#endif
sy = (code&0x1ff)-0x80;
height = (((code>>24)&3)+1)<<3;
if(sy+height <= y_min || sy > y_max) goto nextsprite;
@ -466,40 +554,52 @@ static void DrawAllSpritesFull(int prio, int maxwidth)
}
// Go through sprites backwards:
for (i-- ;i>=0; i--)
for (i--; i >= 0; i--)
{
DrawSpriteFull(sprites[i]);
DrawSpriteFull(sprites[i], est);
}
}
#ifndef _ASM_DRAW_C
static void BackFillFull(int reg7)
static void BackFillFull(unsigned char *dst, int reg7, int lwidth)
{
unsigned int back;
int i;
// Start with a background color:
// back=PicoCramHigh[reg7&0x3f];
back=reg7&0x3f;
back|=back<<8;
back|=back<<16;
memset32((int *)PicoDraw2FB, back, LINE_WIDTH*(8+(END_ROW-START_ROW)*8)/4);
for (i = 0, dst += 8*lwidth; i < (END_ROW-START_ROW)*8; i++, dst += lwidth)
memset32(dst+8, back, 320/4);
}
#endif
static void DrawDisplayFull(void)
{
struct PicoVideo *pvid=&Pico.video;
struct PicoEState *est = &Pico.est;
struct PicoVideo *pvid=&est->Pico->video;
int win, edge=0, hvwin=0; // LSb->MSb: hwin&plane, vwin&plane, full
int planestart=START_ROW, planeend=END_ROW; // plane A start/end when window shares display with plane A (in tile rows or columns)
int winstart=START_ROW, winend=END_ROW; // same for window
int scrstart=START_ROW, scrend = END_ROW; // our render area
int planestart, planeend; // plane A start/end when window shares display with plane A (in tile rows or columns)
int winstart, winend; // same for window
int maxw, maxcolc; // max width and col cells
if(pvid->reg[12]&1) {
maxw = 328; maxcolc = 40;
} else {
if(est->rendstatus & PDRAW_32_COLS) {
maxw = 264; maxcolc = 32;
} else {
maxw = 328; maxcolc = 40;
}
if(est->rendstatus & PDRAW_30_ROWS) {
// In 240 line mode, the top and bottom 8 lines are omitted
// since this renderer always renders 224 lines
scrstart ++, scrend ++;
}
est->Draw2Start = scrstart;
planestart = scrstart, planeend = scrend;
winstart = scrstart, winend = scrend;
// horizontal window?
if ((win=pvid->reg[0x12]))
@ -511,12 +611,12 @@ static void DrawDisplayFull(void)
hvwin=4;
} else if(win < 0x80) {
// window on the top
if(edge <= START_ROW) hvwin=0; // window not visible in our drawing region
else if(edge >= END_ROW) hvwin=4;
if(edge <= scrstart) hvwin=0; // window not visible in our drawing region
else if(edge >= scrend) hvwin=4;
else planestart = winend = edge;
} else if(win > 0x80) {
// window at the bottom
if(edge >= END_ROW) hvwin=0;
if(edge >= scrend) hvwin=0;
else planeend = winstart = edge;
}
}
@ -549,65 +649,65 @@ static void DrawDisplayFull(void)
if (hvwin==1) { winend|=maxcolc<<16; planeend|=maxcolc<<16; }
HighCache2A[1] = HighCache2B[1] = 0;
if (PicoDrawMask & PDRAW_LAYERB_ON)
DrawLayerFull(1, HighCache2B, START_ROW, (maxcolc<<16)|END_ROW);
if (PicoDrawMask & PDRAW_LAYERA_ON) switch (hvwin)
HighCache2A[0] = HighCache2B[0] = 0;
if (!(pvid->debug_p & PVD_KILL_B))
DrawLayerFull(1, HighCache2B, scrstart, (maxcolc<<16)|scrend, est);
if (!(pvid->debug_p & PVD_KILL_A)) switch (hvwin)
{
case 4:
// fullscreen window
DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 0);
DrawWindowFull(scrstart, (maxcolc<<16)|scrend, 0, est);
break;
case 3:
// we have plane A and both v and h windows
DrawLayerFull(0, HighCache2A, planestart, planeend);
DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 0); // h
DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 0); // v
DrawLayerFull(0, HighCache2A, planestart, planeend, est);
DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 0, est); // h
DrawWindowFull((winstart&~0xff)|scrstart, (winend&~0xff)|scrend, 0, est); // v
break;
case 2:
case 1:
// both window and plane A visible, window is vertical XOR horizontal
DrawLayerFull(0, HighCache2A, planestart, planeend);
DrawWindowFull(winstart, winend, 0);
DrawLayerFull(0, HighCache2A, planestart, planeend, est);
DrawWindowFull(winstart, winend, 0, est);
break;
default:
// fullscreen plane A
DrawLayerFull(0, HighCache2A, START_ROW, (maxcolc<<16)|END_ROW);
DrawLayerFull(0, HighCache2A, scrstart, (maxcolc<<16)|scrend, est);
break;
}
if (PicoDrawMask & PDRAW_SPRITES_LOW_ON)
DrawAllSpritesFull(0, maxw);
if (!(pvid->debug_p & PVD_KILL_S_LO))
DrawAllSpritesFull(0, maxw, est);
if (HighCache2B[1]) DrawTilesFromCacheF(HighCache2B);
if (HighCache2A[1]) DrawTilesFromCacheF(HighCache2A);
if (PicoDrawMask & PDRAW_LAYERA_ON) switch (hvwin)
if (HighCache2B[0]) DrawTilesFromCacheF(HighCache2B, est);
if (HighCache2A[0]) DrawTilesFromCacheF(HighCache2A, est);
if (!(pvid->debug_p & PVD_KILL_A)) switch (hvwin)
{
case 4:
// fullscreen window
DrawWindowFull(START_ROW, (maxcolc<<16)|END_ROW, 1);
DrawWindowFull(scrstart, (maxcolc<<16)|scrend, 1, est);
break;
case 3:
// we have plane A and both v and h windows
DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 1); // h
DrawWindowFull((winstart&~0xff)|START_ROW, (winend&~0xff)|END_ROW, 1); // v
DrawWindowFull( winstart&~0xff0000, (winend&~0xff0000)|(maxcolc<<16), 1, est); // h
DrawWindowFull((winstart&~0xff)|scrstart, (winend&~0xff)|scrend, 1, est); // v
break;
case 2:
case 1:
// both window and plane A visible, window is vertical XOR horizontal
DrawWindowFull(winstart, winend, 1);
DrawWindowFull(winstart, winend, 1, est);
break;
}
if (PicoDrawMask & PDRAW_SPRITES_HI_ON)
DrawAllSpritesFull(1, maxw);
if (!(pvid->debug_p & PVD_KILL_S_HI))
DrawAllSpritesFull(1, maxw, est);
}
PICO_INTERNAL void PicoFrameFull()
PICO_INTERNAL void PicoFrameFull(void)
{
pprof_start(draw);
@ -615,10 +715,37 @@ PICO_INTERNAL void PicoFrameFull()
if (PicoPrepareCram) PicoPrepareCram();
// Draw screen:
BackFillFull(Pico.video.reg[7]);
BackFillFull(Pico.est.Draw2FB, Pico.video.reg[7], Pico.est.Draw2Width);
if (Pico.video.reg[1] & 0x40)
DrawDisplayFull();
// clear top and bottom 8 lines in 240 mode, since draw2 only does 224
if (Pico.est.rendstatus & PDRAW_30_ROWS) {
unsigned char *pd = Pico.est.Draw2FB;
int i;
for (i = 8; i > 0; i--, pd += Pico.est.Draw2Width)
memset32((int *)pd, 0xe0e0e0e0, 328/4);
pd += Pico.est.Draw2Width*(END_ROW-START_ROW)*8;
for (i = 8; i > 0; i--, pd += Pico.est.Draw2Width)
memset32((int *)pd, 0xe0e0e0e0, 328/4);
}
pprof_end(draw);
}
void PicoDraw2SetOutBuf(void *dest, int incr)
{
if (dest) {
Pico.est.Draw2FB = dest;
Pico.est.Draw2Width = incr;
} else {
Pico.est.Draw2FB = PicoDraw2FB_;
Pico.est.Draw2Width = LINE_WIDTH;
}
}
void PicoDraw2Init(void)
{
PicoDraw2SetOutBuf(NULL, 0);
}

View file

@ -1,15 +1,22 @@
/*
* assembly optimized versions of most funtions from draw2.c
* (C) notaz, 2006-2008
* (C) irixxxx, 2019-2023
*
* This work is licensed under the terms of MAME license.
* See COPYING file in the top-level directory.
*
* this is highly specialized, be careful if changing related C code!
*
* NB: this only deals with buffers having line width at 328
*/
.extern Pico
.extern PicoDraw2FB
#include "pico_int_offs.h"
.equ PDRAW_INTERLACE, (1<<3)
.equ PDRAW_32_COLS, (1<<8)
.equ PDRAW_BORDER_32, (1<<9)
.equ PDRAW_30_ROWS, (1<<11)
@ define these constants in your include file:
@ .equiv START_ROW, 1
@ -25,16 +32,19 @@
.text
.align 2
.global BackFillFull @ int reg7
@ void BackFillFull(unsigned char *dst, int reg7, int lwidth)
.global BackFillFull
BackFillFull:
stmfd sp!, {r4-r9,lr}
stmfd sp!, {r4-r10,lr}
ldr lr, =PicoDraw2FB @ lr=PicoDraw2FB
mov r0, r0, lsl #26
ldr lr, [lr]
sub r10,r2, #320 @ unused bytes in a line
add lr, r0, #8 @ 8 px overlap area at start of line
add lr, lr, r2, lsl #3 @ 8 lines overlap area at top
mov r0, r1, lsl #26
mov r0, r0, lsr #26
add lr, lr, #328*8
orr r0, r0, r0, lsl #8
orr r0, r0, r0, lsl #16
@ -53,7 +63,6 @@ BackFillFull:
@ go go go!
.bff_loop:
add lr, lr, #8
subs r12, r12, #1
stmia lr!, {r0-r9} @ 10*4*8
@ -65,17 +74,27 @@ BackFillFull:
stmia lr!, {r0-r9}
stmia lr!, {r0-r9}
add lr, lr, r10 @ skip unused rest of line
bne .bff_loop
ldmfd sp!, {r4-r9,r12}
bx r12
ldmfd sp!, {r4-r10,lr}
bx lr
.pool
@ -------- some macros --------
@ helpers
.macro add_c24 d s c
add \d, \s, #(\c & 0x00ff00)
.if \c & 0x0000ff
add \d, \d, #(\c & 0x0000ff)
.endif
.if \c & 0xff0000
add \d, \d, #(\c & 0xff0000)
.endif
.endm
@ helper
@ TileLineSinglecol (r1=pdest, r2=pixels8, r3=pal) r4: scratch, r0: pixels8_old
.macro TileLineSinglecol notsinglecol=0
and r2, r2, #0xf @ #0x0000000f
@ -343,19 +362,21 @@ BackFillFull:
@ DrawLayerTiles(*hcache, *scrpos, (cells<<24)|(nametab<<9)|(vscroll&0x3ff)<<11|(shift[width]<<8)|planeend, (ymask<<24)|(planestart<<16)|[htab||hscroll]
@static void DrawLayerFull(int plane, int *hcache, int planestart, int planeend)
@ void DrawLayerFull(int plane, int *hcache, int planestart, int planeend,
@ struct PicoEState *est)
.global DrawLayerFull
DrawLayerFull:
ldr r12,[sp] @ est
stmfd sp!, {r4-r11,lr}
mov r6, r1 @ hcache
ldr r11, =(Pico+0x22228) @ Pico.video
ldr r10, =(Pico+0x10000) @ r10=Pico.vram
ldrb r5, [r11, #13] @ pvid->reg[13]
ldrb r7, [r11, #11]
ldr r11, [r12, #OFS_EST_Pico]
ldr r10, [r12, #OFS_EST_PicoMem_vram]
ldrb r5, [r11, #OFS_Pico_video_reg+13] @ pvid->reg[13]
ldrb r7, [r11, #OFS_Pico_video_reg+11]
sub lr, r3, r2
and lr, lr, #0x00ff0000 @ lr=cells
@ -365,7 +386,7 @@ DrawLayerFull:
bic r5, r5, #0x00ff0000 @ just in case
tst r7, #3 @ full screen scroll? (if ==0)
ldrb r7, [r11, #16] @ ??hh??ww
ldrb r7, [r11, #OFS_Pico_video_reg+16] @ ??hh??ww
ldreqh r5, [r10, r5]
biceq r5, r5, #0x0000fc00 @ r5=hscroll (0-0x3ff)
movne r5, r5, lsr #1
@ -396,22 +417,26 @@ DrawLayerFull:
@ Find name table:
tst r0, r0
ldreqb r4, [r11, #2]
ldreqb r4, [r11, #OFS_Pico_video_reg+2]
moveq r4, r4, lsr #3
ldrneb r4, [r11, #4]
ldrneb r4, [r11, #OFS_Pico_video_reg+4]
and r4, r4, #7
orr lr, lr, r4, lsl #13 @ lr|=nametab_bits{3}<<13
ldr r11, =PicoDraw2FB @ r11=PicoDraw2FB
sub r4, r9, #(START_ROW<<24)
ldr r11, [r11]
ldr r11,[sp, #9*4] @ est
ldr r4, [r11, #OFS_EST_Draw2Start]
ldr r7, [r11, #OFS_EST_rendstatus]
ldr r11, [r11, #OFS_EST_Draw2FB]
sub r4, r9, r4, lsl #24
tst r7, #PDRAW_BORDER_32 @ H32 border mode?
tstne r7, #PDRAW_32_COLS
addne r11, r11, #32
mov r4, r4, asr #24
mov r7, #328*8
mla r11, r4, r7, r11 @ scrpos+=8*328*(planestart-START_ROW);
mla r11, r4, r7, r11 @ scrpos+=8*328*(planestart-Draw2Start);
@ Get vertical scroll value:
add r7, r10, #0x012000
add r7, r7, #0x000180 @ r7=Pico.vsram (Pico+0x22180)
add_c24 r7, r10, (OFS_PMEM_vsram-OFS_PMEM_vram)
ldr r7, [r7]
tst r0, r0
moveq r7, r7, lsl #22
@ -571,23 +596,28 @@ DrawLayerFull:
.pool
@ void DrawTilesFromCacheF(int *hc, struct PicoEState *est)
.global DrawTilesFromCacheF @ int *hc
.global DrawTilesFromCacheF
DrawTilesFromCacheF:
stmfd sp!, {r4-r10,lr}
stmfd sp!, {r4-r11,lr}
mov r9, #0xff000000 @ r9=prevcode=-1
mvn r6, #0 @ r6=prevy=-1
ldr r4, =PicoDraw2FB @ r4=PicoDraw2FB
ldr r1, [r0], #4 @ read y offset
ldr r4, [r4]
ldr r7, [r1, #OFS_EST_rendstatus]
ldr r4, [r1, #OFS_EST_Draw2FB]
ldr r11,[r1, #OFS_EST_Draw2Start]
ldr r2, [r0], #4 @ read y offset
tst r7, #PDRAW_BORDER_32 @ H32 border mode?
tstne r7, #PDRAW_32_COLS
addne r4, r4, #32
mov r7, #328
mla r1, r7, r1, r4
sub r12, r1, #(328*8*START_ROW) @ r12=scrpos
mla r2, r7, r2, r4
sub r12, r2, #(328*8*START_ROW) @ r12=scrpos
ldr r10, =(Pico+0x10000) @ r10=Pico.vram
ldr r10, [r1, #OFS_EST_PicoMem_vram]
mov r8, r0 @ hc
mov r0, #0xf
@ -597,13 +627,14 @@ DrawTilesFromCacheF:
.dtfcf_loop:
ldr r7, [r8], #4 @ read code
movs r1, r7, lsr #16 @ r1=dx;
ldmeqfd sp!, {r4-r10,pc} @ dx is never zero, this must be a terminator, return
ldmeqfd sp!, {r4-r11,pc} @ dx is never zero, this must be a terminator, return
@ row changed?
cmp r6, r7, lsr #27
movne r6, r7, lsr #27
subne r6, r6, r11
movne r4, #328*8
mlane r5, r4, r6, r12 @ r5=pd = scrpos + prevy*328*8
mlane r5, r4, r6, r12 @ r5=pd = scrpos + (prevy-Draw2Start)*328*8
bic r1, r1, #0xf800
add r1, r5, r1 @ r1=pdest (halfwords)
@ -666,31 +697,41 @@ DrawTilesFromCacheF:
@ @@@@@@@@@@@@@@@
@ (tile_start<<16)|row_start
.global DrawWindowFull @ int tstart, int tend, int prio
@ void DrawWindowFull(int start, int end, int prio, struct PicoEState *est)
.global DrawWindowFull
DrawWindowFull:
stmfd sp!, {r4-r11,lr}
ldr r11, =(Pico+0x22228) @ Pico.video
ldrb r12, [r11, #3] @ pvid->reg[3]
ldr r11, [r3, #OFS_EST_Pico]
ldrb r12, [r11, #OFS_Pico_video_reg+3] @ pvid->reg[3]
mov r12, r12, lsl #10
ldr r4, [r11, #12]
ldr r4, [r11, #OFS_Pico_video_reg+12]
mov r5, #1 @ nametab_step
ldr r11, [r3, #OFS_EST_Draw2FB]
ldr r6, [r3, #OFS_EST_Draw2Start]
tst r4, #1 @ 40 cell mode?
andne r12, r12, #0xf000 @ 0x3c<<10
andeq r12, r12, #0xf800
movne r5, r5, lsl #7
moveq r5, r5, lsl #6 @ nametab_step
bne 0f
ldr r7, [r3, #OFS_EST_rendstatus]
and r12, r12, #0xf800
mov r5, r5, lsl #6 @ nametab_step
tst r7, #PDRAW_BORDER_32
tstne r7, #PDRAW_32_COLS
addne r11, r11, #32 @ center screen in H32 mode
and r4, r0, #0xff
mla r12, r5, r4, r12 @ nametab += nametab_step*start;
0: and r4, r0, #0xff
sub r4, r4, r6
mla r12, r5, r4, r12 @ nametab += nametab_step*(start-Draw2Start];
ldr r10, [r3, #OFS_EST_PicoMem_vram]
mov r4, r0, lsr #16 @ r4=start_cell_h
add r7, r12, r4, lsl #1
@ fetch the first code now
ldr r10, =(Pico+0x10000) @ lr=Pico.vram
ldrh r7, [r10, r7]
cmp r2, r7, lsr #15
ldmnefd sp!, {r4-r11,pc} @ hack: simply assume that whole window uses same priority
@ -704,15 +745,13 @@ DrawWindowFull:
mov r9, #0xff000000 @ r9=prevcode=-1
ldr r11, =PicoDraw2FB @ r11=scrpos
and r4, r0, #0xff
ldr r11, [r11]
sub r4, r4, #START_ROW
add r11, r11, #328*8
sub r4, r4, r6
add r11, r11, #8
mov r7, #328*8
mla r11, r7, r4, r11 @ scrpos+=8*328*(start-START_ROW);
mla r11, r7, r4, r11 @ scrpos+=8*328*(start-Draw2Start);
mov r0, #0xf
.dwfloop_outer:
@ -758,7 +797,8 @@ DrawWindowFull:
tst r9, #0x080000 @ hflip?
bne .dwf_hflip
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=PicoMem.vram)
@ r2,r4,r7: scratch, r0=0xf
Tile 0, 0
b .dwfloop
@ -868,13 +908,15 @@ DrawWindowFull:
cmp r6, #(END_ROW*8+8)
bge 52b
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=Pico.vram) r2,r4,r7: scratch, r0=0xf
@ Tile (r1=pdest, r3=pal, r9=prevcode, r10=PicoMem.vram)
@ r2,r4,r7: scratch, r0=0xf
Tile \hflip, \vflip
b 52b
.endm
@ void DrawSpriteFull(unsigned int *sprite, struct PicoEState *est)
.global DrawSpriteFull @ unsigned int *sprite
.global DrawSpriteFull
DrawSpriteFull:
stmfd sp!, {r4-r11,lr}
@ -902,12 +944,16 @@ DrawSpriteFull:
and r3, lr, #0x6000
mov r3, r3, lsr #9 @ r3=pal=((code>>9)&0x30);
ldr r11, =PicoDraw2FB @ r11=scrpos
ldr r10, =(Pico+0x10000) @ r10=Pico.vram
ldr r11, [r11]
sub r1, r12, #(START_ROW*8)
ldr r0, [r1, #OFS_EST_rendstatus]
ldr r11, [r1, #OFS_EST_Draw2FB]
ldr r2, [r1, #OFS_EST_Draw2Start]
ldr r10, [r1, #OFS_EST_PicoMem_vram]
tst r0, #PDRAW_BORDER_32 @ H32 border mode?
tstne r0, #PDRAW_32_COLS
addne r11, r11, #32
sub r12, r12, r2, lsl #3
mov r0, #328
mla r11, r1, r0, r11 @ scrpos+=(sy-START_ROW*8)*328;
mla r11, r12, r0, r11 @ scrpos+=(sy-Draw2Start*8)*328;
orr r5, r5, r5, lsl #16 @
orr r5, r6, r5, lsl #8 @ r5=width|(height<<8)|(height<<24)

File diff suppressed because it is too large Load diff

View file

@ -42,14 +42,14 @@ static void EEPROM_write_do(unsigned int d) // ???? ??la (l=SCL, a=SDA)
{
// we are started and SCL went high - next cycle
scyc++; // pre-increment
if(SRam.eeprom_type) {
if(Pico.sv.eeprom_type) {
// X24C02+
if((ssa&1) && scyc == 18) {
scyc = 9;
saddr++; // next address in read mode
/*if(SRam.eeprom_type==2) saddr&=0xff; else*/ saddr&=0x1fff; // mask
/*if(Pico.sv.eeprom_type==2) saddr&=0xff; else*/ saddr&=0x1fff; // mask
}
else if(SRam.eeprom_type == 2 && scyc == 27) scyc = 18;
else if(Pico.sv.eeprom_type == 2 && scyc == 27) scyc = 18;
else if(scyc == 36) scyc = 27;
} else {
// X24C01
@ -63,29 +63,29 @@ static void EEPROM_write_do(unsigned int d) // ???? ??la (l=SCL, a=SDA)
else if((sreg & 8) && (sreg & 2) && !(d&2))
{
// we are started and SCL went low (falling edge)
if(SRam.eeprom_type) {
if(Pico.sv.eeprom_type) {
// X24C02+
if(scyc == 9 || scyc == 18 || scyc == 27); // ACK cycles
else if( (SRam.eeprom_type == 3 && scyc > 27) || (SRam.eeprom_type == 2 && scyc > 18) ) {
else if( (Pico.sv.eeprom_type == 3 && scyc > 27) || (Pico.sv.eeprom_type == 2 && scyc > 18) ) {
if(!(ssa&1)) {
// data write
unsigned char *pm=SRam.data+saddr;
unsigned char *pm=Pico.sv.data+saddr;
*pm <<= 1; *pm |= d&1;
if(scyc == 26 || scyc == 35) {
saddr=(saddr&~0xf)|((saddr+1)&0xf); // only 4 (?) lowest bits are incremented
elprintf(EL_EEPROM, "eeprom: write done, addr inc to: %x, last byte=%02x", saddr, *pm);
}
SRam.changed = 1;
Pico.sv.changed = 1;
}
} else if(scyc > 9) {
if(!(ssa&1)) {
// we latch another addr bit
saddr<<=1;
if(SRam.eeprom_type == 2) saddr&=0xff; else saddr&=0x1fff; // mask
if(Pico.sv.eeprom_type == 2) saddr&=0xff; else saddr&=0x1fff; // mask
saddr|=d&1;
if(scyc==17||scyc==26) {
elprintf(EL_EEPROM, "eeprom: addr reg done: %x", saddr);
if(scyc==17&&SRam.eeprom_type==2) { saddr&=0xff; saddr|=(ssa<<7)&0x700; } // add device bits too
if(scyc==17&&Pico.sv.eeprom_type==2) { saddr&=0xff; saddr|=(ssa<<7)&0x700; } // add device bits too
}
}
} else {
@ -99,13 +99,13 @@ static void EEPROM_write_do(unsigned int d) // ???? ??la (l=SCL, a=SDA)
else if(scyc > 9) {
if(!(saddr&1)) {
// data write
unsigned char *pm=SRam.data+(saddr>>1);
unsigned char *pm=Pico.sv.data+(saddr>>1);
*pm <<= 1; *pm |= d&1;
if(scyc == 17) {
saddr=(saddr&0xf9)|((saddr+2)&6); // only 2 lowest bits are incremented
elprintf(EL_EEPROM, "eeprom: write done, addr inc to: %x, last byte=%02x", saddr>>1, *pm);
}
SRam.changed = 1;
Pico.sv.changed = 1;
}
} else {
// we latch another addr bit
@ -129,11 +129,11 @@ static void EEPROM_upd_pending(unsigned int d)
sreg &= ~0xc0;
// SCL
d1 = (d >> SRam.eeprom_bit_cl) & 1;
d1 = (d >> Pico.sv.eeprom_bit_cl) & 1;
sreg |= d1 << 7;
// SDA in
d1 = (d >> SRam.eeprom_bit_in) & 1;
d1 = (d >> Pico.sv.eeprom_bit_in) & 1;
sreg |= d1 << 6;
Pico.m.eeprom_status = (unsigned char) sreg;
@ -190,23 +190,23 @@ unsigned int EEPROM_read(void)
} else if (scyc > 9 && scyc < 18) {
// started and first command word received
shift = 17-scyc;
if (SRam.eeprom_type) {
if (Pico.sv.eeprom_type) {
// X24C02+
if (ssa&1) {
elprintf(EL_EEPROM, "eeprom: read: addr %02x, cycle %i, reg %02x", saddr, scyc, sreg);
if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", SRam.data[saddr]);
d = (SRam.data[saddr]>>shift)&1;
if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", Pico.sv.data[saddr]);
d = (Pico.sv.data[saddr]>>shift)&1;
}
} else {
// X24C01
if (saddr&1) {
elprintf(EL_EEPROM, "eeprom: read: addr %02x, cycle %i, reg %02x", saddr>>1, scyc, sreg);
if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", SRam.data[saddr>>1]);
d = (SRam.data[saddr>>1]>>shift)&1;
if (shift==0) elprintf(EL_EEPROM, "eeprom: read done, byte %02x", Pico.sv.data[saddr>>1]);
d = (Pico.sv.data[saddr>>1]>>shift)&1;
}
}
}
return (d << SRam.eeprom_bit_out);
return (d << Pico.sv.eeprom_bit_out);
}

View file

@ -27,18 +27,18 @@ cyclone_checkpc:
and r3, r0, #0xff000000
bic r0, r0, #1
bics r2, r0, #0xff000000
beq crashed
@ ouf, some Codemasters titles actually start at address 0
@ beq crashed
ldr r1, [r7, #0x6c] @ read16 map
mov r2, r2, lsr #M68K_MEM_SHIFT
ldr r1, [r1, r2, lsl #2]
movs r1, r1, lsl #1
bcs crashed
sub r1, r1, r3
str r1, [r7, #0x60] @ membase
add r0, r0, r1
bx lr
movs r1, r1, lsl #1
subcc r1, r1, r3
strcc r1, [r7, #0x60] @ membase
addcc r0, r0, r1
bxcc lr
crashed:
stmfd sp!,{lr}
@ -82,24 +82,24 @@ cyclone_fetch32:
ldr r1, [r1, r2, lsl #2]
bic r0, r0, #1
movs r1, r1, lsl #1
ldrcch r0, [r1, r0]!
ldrcch r2, [r1, r0]!
ldrcch r1, [r1, #2]
orrcc r0, r1, r0, lsl #16
orrcc r0, r1, r2, lsl #16
bxcc lr
stmfd sp!,{r0,r1,lr}
stmfd sp!,{r0,r1,r2,lr}
mov lr, pc
bx r1
mov r2, r0, lsl #16
ldmia sp, {r0,r1}
ldmfd sp!, {r0,r1}
str r2, [sp]
add r0, r0, #2
mov lr, pc
bx r1
ldr r1, [sp]
ldmfd sp!, {r1,lr}
mov r0, r0, lsl #16
orr r0, r1, r0, lsr #16
ldmfd sp!,{r1,r2,pc}
bx lr
cyclone_write8: @ u32 a, u8 d

View file

@ -8,7 +8,7 @@
#include <string.h>
#include "pico_int.h"
#include "cd/cue.h"
#include "cd/cd_parse.h"
unsigned char media_id_header[0x100];
@ -31,34 +31,50 @@ static void get_ext(const char *file, char *ext)
strlwr_(ext);
}
static int detect_media(const char *fname)
static int detect_media(const char *fname, const unsigned char *rom, unsigned int romsize)
{
static const short sms_offsets[] = { 0x7ff0, 0x3ff0, 0x1ff0 };
static const char *sms_exts[] = { "sms", "gg", "sg" };
static const char *md_exts[] = { "gen", "bin", "smd" };
char buff0[32], buff[32];
unsigned short *d16;
pm_file *pmf;
char ext[5];
static const char *sms_exts[] = { "sms", "gg", "sg", "sc" };
static const char *md_exts[] = { "gen", "smd", "md", "32x" };
static const char *pico_exts[] = { "pco" };
char buff0[512], buff[32];
unsigned short *d16 = NULL;
pm_file *pmf = NULL;
const char *ext_ptr = NULL;
char ext[8];
int i;
get_ext(fname, ext);
ext[0] = '\0';
if ((ext_ptr = strrchr(fname, '.'))) {
strncpy(ext, ext_ptr + 1, sizeof(ext));
ext[sizeof(ext) - 1] = '\0';
}
// detect wrong extensions
if (!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) // s.gz ~ .mds.gz
if (!strcasecmp(ext, "srm") || !strcasecmp(ext, "gz")) // s.gz ~ .mds.gz
return PM_BAD_DETECT;
/* don't believe in extensions, except .cue */
if (strcasecmp(ext, ".cue") == 0)
/* don't believe in extensions, except .cue and .chd */
if (strcasecmp(ext, "cue") == 0 || strcasecmp(ext, "chd") == 0)
return PM_CD;
pmf = pm_open(fname);
if (pmf == NULL)
return PM_BAD_DETECT;
/* Open rom file, if required */
if (!rom) {
pmf = pm_open(fname);
if (pmf == NULL)
return PM_BAD_DETECT;
romsize = pmf->size;
}
if (pm_read(buff0, 32, pmf) != 32) {
pm_close(pmf);
return PM_BAD_DETECT;
if (!rom) {
if (pm_read(buff0, 512, pmf) != 512) {
pm_close(pmf);
return PM_BAD_DETECT;
}
} else {
if (romsize < 512)
return PM_BAD_DETECT;
memcpy(buff0, rom, 512);
}
if (strncasecmp("SEGADISCSYSTEM", buff0 + 0x00, 14) == 0 ||
@ -68,28 +84,53 @@ static int detect_media(const char *fname)
}
/* check for SMD evil */
if (pmf->size >= 0x4200 && (pmf->size & 0x3fff) == 0x200) {
if (pm_seek(pmf, sms_offsets[0] + 0x200, SEEK_SET) == sms_offsets[0] + 0x200 &&
pm_read(buff, 16, pmf) == 16 &&
strncmp("TMR SEGA", buff, 8) == 0)
if (romsize >= 0x4200 && (romsize & 0x3fff) == 0x200) {
buff[0] = '\0';
if (!rom) {
if (pm_seek(pmf, sms_offsets[0] + 0x200, SEEK_SET) == sms_offsets[0] + 0x200)
pm_read(buff, 16, pmf);
} else {
if (romsize >= sms_offsets[0] + 0x200 + 16)
memcpy(buff, rom + sms_offsets[0] + 0x200, 16);
}
if (strncmp("TMR SEGA", buff, 8) == 0)
goto looks_like_sms;
/* could parse further but don't bother */
goto extension_check;
}
/* MD header? Act as TMSS BIOS here */
if (pm_seek(pmf, 0x100, SEEK_SET) == 0x100 && pm_read(buff, 16, pmf) == 16) {
if (strncmp(buff, "SEGA", 4) == 0 || strncmp(buff, " SEG", 4) == 0)
goto looks_like_md;
/* fetch header info */
memset(buff, '\0', 17);
if (!rom) {
if (pm_seek(pmf, 0x100, SEEK_SET) == 0x100)
pm_read(buff, 16, pmf);
} else {
if (romsize >= 0x100 + 16)
memcpy(buff, rom + 0x100, 16);
}
/* PICO header? Almost always appropriately marked */
if (strstr(buff, " PICO "))
goto looks_like_pico;
/* MD header? Act as TMSS BIOS here */
if (strncmp(buff, "SEGA", 4) == 0 || strncmp(buff, " SEG", 4) == 0)
goto looks_like_md;
for (i = 0; i < ARRAY_SIZE(sms_offsets); i++) {
if (pm_seek(pmf, sms_offsets[i], SEEK_SET) != sms_offsets[i])
continue;
if (!rom) {
if (pm_seek(pmf, sms_offsets[i], SEEK_SET) != sms_offsets[i])
continue;
if (pm_read(buff, 16, pmf) != 16)
continue;
if (pm_read(buff, 16, pmf) != 16)
continue;
} else {
if (romsize < sms_offsets[i] + 16)
continue;
memcpy(buff, rom + sms_offsets[i], 16);
}
if (strncmp("TMR SEGA", buff, 8) == 0)
goto looks_like_sms;
@ -97,20 +138,31 @@ static int detect_media(const char *fname)
extension_check:
/* probably some headerless thing. Maybe check the extension after all. */
ext_ptr = pmf && *pmf->ext ? pmf->ext : ext;
for (i = 0; i < ARRAY_SIZE(md_exts); i++)
if (strcasecmp(pmf->ext, md_exts[i]) == 0)
if (strcasecmp(ext_ptr, md_exts[i]) == 0)
goto looks_like_md;
for (i = 0; i < ARRAY_SIZE(sms_exts); i++)
if (strcasecmp(pmf->ext, sms_exts[i]) == 0)
if (strcasecmp(ext_ptr, sms_exts[i]) == 0)
goto looks_like_sms;
for (i = 0; i < ARRAY_SIZE(pico_exts); i++)
if (strcasecmp(ext_ptr, pico_exts[i]) == 0)
goto looks_like_pico;
/* If everything else fails, make a guess on the reset vector */
d16 = (unsigned short *)(buff0 + 4);
if ((((d16[0] << 16) | d16[1]) & 0xffffff) >= pmf->size) {
if ((((d16[0] << 16) | d16[1]) & 0xffffff) >= romsize) {
lprintf("bad MD reset vector, assuming SMS\n");
goto looks_like_sms;
}
d16 = (unsigned short *)(buff0 + 0x1a0);
if ((((d16[0] << 16) | d16[1]) & 0xffffff) != 0) {
lprintf("bad MD rom start, assuming SMS\n");
goto looks_like_sms;
}
looks_like_md:
pm_close(pmf);
@ -119,6 +171,10 @@ looks_like_md:
looks_like_sms:
pm_close(pmf);
return PM_MARK3;
looks_like_pico:
pm_close(pmf);
return PM_PICO;
}
/* checks if fname points to valid MegaCD image */
@ -129,26 +185,31 @@ int PicoCdCheck(const char *fname_in, int *pregion)
pm_file *cd_f;
int region = 4; // 1: Japan, 4: US, 8: Europe
char ext[5];
cue_track_type type = CT_UNKNOWN;
cue_data_t *cue_data = NULL;
enum cd_track_type type = CT_UNKNOWN;
cd_data_t *cd_data = NULL;
// opens a cue, or searches for one
cue_data = cue_parse(fname_in);
if (cue_data != NULL) {
fname = cue_data->tracks[1].fname;
type = cue_data->tracks[1].type;
}
else {
if (!cd_data && (cd_data = cue_parse(fname_in)) == NULL) {
get_ext(fname_in, ext);
if (strcasecmp(ext, ".cue") == 0)
return -1;
}
// opens a chd
if (!cd_data && (cd_data = chd_parse(fname_in)) == NULL) {
get_ext(fname_in, ext);
if (strcasecmp(ext, ".chd") == 0)
return -1;
}
if (cd_data != NULL) {
// 1st track contains the code
fname = cd_data->tracks[1].fname;
type = cd_data->tracks[1].type;
}
cd_f = pm_open(fname);
if (cue_data != NULL)
cue_destroy(cue_data);
if (cd_f == NULL) return 0; // let the upper level handle this
cdparse_destroy(cd_data);
if (cd_f == NULL) return CT_UNKNOWN; // let the upper level handle this
if (pm_read(buf, 32, cd_f) != 32) {
pm_close(cd_f);
@ -192,34 +253,35 @@ int PicoCdCheck(const char *fname_in, int *pregion)
}
enum media_type_e PicoLoadMedia(const char *filename,
const unsigned char *rom, unsigned int romsize,
const char *carthw_cfg_fname,
const char *(*get_bios_filename)(int *region, const char *cd_fname),
void (*do_region_override)(const char *media_filename))
{
const char *rom_fname = filename;
enum media_type_e media_type;
enum cd_img_type cd_img_type = CIT_NOT_CD;
enum cd_track_type cd_img_type = CT_UNKNOWN;
pm_file *rom_file = NULL;
unsigned char *rom_data = NULL;
unsigned int rom_size = 0;
pm_file *rom = NULL;
int cd_region = 0;
int ret;
media_type = detect_media(filename);
media_type = detect_media(filename, rom, romsize);
if (media_type == PM_BAD_DETECT)
goto out;
if ((PicoAHW & PAHW_MCD) && Pico_mcd != NULL)
if ((PicoIn.AHW & PAHW_MCD) && Pico_mcd != NULL)
cdd_unload();
PicoCartUnload();
PicoAHW = 0;
PicoQuirks = 0;
PicoIn.AHW = 0;
PicoIn.quirks = 0;
if (media_type == PM_CD)
{
// check for MegaCD image
cd_img_type = PicoCdCheck(filename, &cd_region);
if ((int)cd_img_type >= 0 && cd_img_type != CIT_NOT_CD)
if ((int)cd_img_type >= 0 && cd_img_type != CT_UNKNOWN)
{
// valid CD image, ask frontend for BIOS..
rom_fname = NULL;
@ -230,7 +292,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
goto out;
}
PicoAHW |= PAHW_MCD;
PicoIn.AHW |= PAHW_MCD;
}
else {
media_type = PM_BAD_CD;
@ -238,23 +300,26 @@ enum media_type_e PicoLoadMedia(const char *filename,
}
}
else if (media_type == PM_MARK3) {
lprintf("detected SMS ROM\n");
PicoAHW = PAHW_SMS;
PicoIn.AHW = PAHW_SMS;
}
else if (media_type == PM_PICO) {
PicoIn.AHW = PAHW_PICO;
}
rom = pm_open(rom_fname);
if (rom == NULL) {
lprintf("Failed to open ROM");
media_type = PM_ERROR;
goto out;
if (!rom) {
rom_file = pm_open(rom_fname);
if (rom_file == NULL) {
lprintf("Failed to open ROM\n");
media_type = PM_ERROR;
goto out;
}
}
ret = PicoCartLoad(rom, &rom_data, &rom_size, (PicoAHW & PAHW_SMS) ? 1 : 0);
pm_close(rom);
ret = PicoCartLoad(rom_file, rom, romsize, &rom_data, &rom_size, (PicoIn.AHW & PAHW_SMS) ? 1 : 0);
if (ret != 0) {
if (ret == 2) lprintf("Out of memory");
else if (ret == 3) lprintf("Read failed");
else lprintf("PicoCartLoad() failed.");
if (ret == 2) lprintf("Out of memory\n");
else if (ret == 3) lprintf("Read failed\n");
else lprintf("PicoCartLoad() failed.\n");
media_type = PM_ERROR;
goto out;
}
@ -266,7 +331,7 @@ enum media_type_e PicoLoadMedia(const char *filename,
goto out;
}
if (!(PicoAHW & PAHW_SMS)) {
if (!(PicoIn.AHW & PAHW_SMS)) {
unsigned short *d = (unsigned short *)(rom_data + 4);
if ((((d[0] << 16) | d[1]) & 0xffffff) >= (int)rom_size) {
lprintf("bad reset vector\n");
@ -276,36 +341,63 @@ enum media_type_e PicoLoadMedia(const char *filename,
}
// load config for this ROM (do this before insert to get correct region)
if (!(PicoAHW & PAHW_MCD)) {
if (!(PicoIn.AHW & PAHW_MCD)) {
memcpy(media_id_header, rom_data + 0x100, sizeof(media_id_header));
if (do_region_override != NULL)
do_region_override(filename);
}
// simple test for GG. Do this here since m.hardware is nulled in Insert
if ((PicoIn.AHW & PAHW_SMS) && !PicoIn.hwSelect) {
const char *ext = NULL;
if (rom_file && (*rom_file->ext != '\0')) {
ext = rom_file->ext;
}
else if ((ext = strrchr(filename, '.'))) {
if (*(++ext) == '\0') {
ext = NULL;
}
}
if (ext && !strcasecmp(ext,"gg")) {
PicoIn.AHW |= PAHW_GG;
lprintf("detected GG ROM\n");
} else if (ext && !strcasecmp(ext,"sg")) {
PicoIn.AHW |= PAHW_SG;
lprintf("detected SG-1000 ROM\n");
} else if (ext && !strcasecmp(ext,"sc")) {
PicoIn.AHW |= PAHW_SC;
lprintf("detected SC-3000 ROM\n");
} else
lprintf("detected SMS ROM\n");
}
if (PicoCartInsert(rom_data, rom_size, carthw_cfg_fname)) {
media_type = PM_ERROR;
goto out;
}
rom_data = NULL; // now belongs to PicoCart
Pico.m.ncart_in = 0;
// insert CD if it was detected
if (cd_img_type != CIT_NOT_CD) {
Pico.m.ncart_in = 0;
if (cd_img_type != CT_UNKNOWN) {
ret = cdd_load(filename, cd_img_type);
if (ret != 0) {
PicoCartUnload();
media_type = PM_BAD_CD;
goto out;
}
Pico.m.ncart_in = 1;
if (Pico.romsize <= 0x20000)
Pico.m.ncart_in = 1;
}
if (PicoQuirks & PQUIRK_FORCE_6BTN)
if (PicoIn.quirks & PQUIRK_FORCE_6BTN)
PicoSetInputDevice(0, PICO_INPUT_PAD_6BTN);
out:
if (rom_file)
pm_close(rom_file);
if (rom_data)
free(rom_data);
PicoCartUnload();
return media_type;
}

File diff suppressed because it is too large Load diff

View file

@ -1,9 +1,6 @@
// memory map related stuff
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long uptr; // unsigned pointer-sized int
#include "pico_port.h"
#define M68K_MEM_SHIFT 16
// minimum size we can map
@ -28,22 +25,34 @@ typedef void (cpu68k_write_f)(u32 a, u32 d);
extern u32 m68k_read8(u32 a);
extern u32 m68k_read16(u32 a);
extern u32 m68k_read32(u32 a);
extern void m68k_write8(u32 a, u8 d);
extern void m68k_write16(u32 a, u16 d);
extern void m68k_write32(u32 a, u32 d);
extern u32 s68k_read8(u32 a);
extern u32 s68k_read16(u32 a);
extern u32 s68k_read32(u32 a);
extern void s68k_write8(u32 a, u8 d);
extern void s68k_write16(u32 a, u16 d);
extern void s68k_write32(u32 a, u32 d);
// z80
#define Z80_MEM_SHIFT 13
#define Z80_MEM_SHIFT 10 // must be <=10 to allow 1KB pages for SMS Sega mapper
extern uptr z80_read_map [0x10000 >> Z80_MEM_SHIFT];
extern uptr z80_write_map[0x10000 >> Z80_MEM_SHIFT];
typedef unsigned char (z80_read_f)(unsigned short a);
typedef void (z80_write_f)(unsigned int a, unsigned char data);
void z80_map_set(uptr *map, int start_addr, int end_addr,
void z80_map_set(uptr *map, u16 start_addr, u16 end_addr,
const void *func_or_mh, int is_func);
void cpu68k_map_set(uptr *map, int start_addr, int end_addr,
void cpu68k_map_set(uptr *map, u32 start_addr, u32 end_addr,
const void *func_or_mh, int is_func);
void cpu68k_map_all_ram(int start_addr, int end_addr, void *ptr, int is_sub);
void m68k_map_unmap(int start_addr, int end_addr);
void cpu68k_map_read_mem(u32 start_addr, u32 end_addr, void *ptr, int is_sub);
void cpu68k_map_all_ram(u32 start_addr, u32 end_addr, void *ptr, int is_sub);
void cpu68k_map_read_funcs(u32 start_addr, u32 end_addr, u32 (*r8)(u32), u32 (*r16)(u32), int is_sub);
void cpu68k_map_all_funcs(u32 start_addr, u32 end_addr, u32 (*r8)(u32), u32 (*r16)(u32), void (*w8)(u32, u32), void (*w16)(u32, u32), int is_sub);
void m68k_map_unmap(u32 start_addr, u32 end_addr);
#define MAP_FLAG ((uptr)1 << (sizeof(uptr) * 8 - 1))
#define map_flag_set(x) ((x) & MAP_FLAG)
@ -57,7 +66,7 @@ u32 name(u32 a) \
if (map_flag_set(v)) \
return ((cpu68k_read_f *)(v << 1))(a); \
else \
return *(u8 *)((v << 1) + (a ^ 1)); \
return *(u8 *)((v << 1) + MEM_BE2(a)); \
}
#define MAKE_68K_READ16(name, map) \
@ -100,7 +109,7 @@ void name(u32 a, u8 d) \
if (map_flag_set(v)) \
((cpu68k_write_f *)(v << 1))(a, d); \
else \
*(u8 *)((v << 1) + (a ^ 1)) = d; \
*(u8 *)((v << 1) + MEM_BE2(a)) = d; \
}
#define MAKE_68K_WRITE16(name, map) \
@ -133,6 +142,25 @@ void name(u32 a, u32 d) \
} \
}
#ifdef NEED_DMA_SOURCE // meh
static __inline void *m68k_dma_source(u32 a)
{
u8 *base;
uptr v;
v = m68k_read16_map[a >> M68K_MEM_SHIFT];
if (map_flag_set(v)) {
if (a >= Pico.romsize) // Rom
return NULL;
base = Pico.rom;
}
else
base = (void *)(v << 1);
return base + (a & 0xfe0000);
}
#endif
// 32x
typedef struct {
uptr addr; // stores (membase >> 1) or ((handler >> 1) | (1<<31))

View file

@ -8,6 +8,8 @@
# OUT OF DATE
#include "pico_int_offs.h"
.set noreorder
.set noat
@ -184,8 +186,8 @@ m_read32_table:
PicoMemReset:
lui $v1, %hi(Pico+0x22204)
lw $v1, %lo(Pico+0x22204)($v1) # romsize
lui $v1, %hi(Pico+OFS_Pico_romsize)
lw $v1, %lo(Pico+OFS_Pico_romsize)($v1) # romsize
lui $t0, 8
addu $v1, $t0
addiu $v1, -1
@ -235,12 +237,11 @@ m_read_neg1:
jr $ra
addiu $v0, $0, 0xffff
# loads &Pico.rom to $t3
# loads &Pico to $t3
.macro m_read_rom_try_sram is200000 size
lui $t2, %hi(SRam)
addiu $t2, %lo(SRam)
lui $t3, %hi(Pico+0x22200)
lw $t1, 8($t2) # SRam.end
lui $t2, %hi(Pico)
addiu $t2, %lo(Pico)
lw $t1, OFS_Pico_sv_end($t2)
.if \is200000
ins $a0, $0, 19, 13
lui $t4, 0x20
@ -248,12 +249,11 @@ m_read_neg1:
.endif
subu $t4, $a0, $t1
bgtz $t4, 1f
addiu $t3, %lo(Pico+0x22200)
lw $t1, 4($t2) # SRam.start
lw $t1, OFS_Pico_sv_start($t2)
subu $t4, $t1, $a0
bgtz $t4, 1f
nop
lb $t1, 0x11($t3) # Pico.m.sram_reg
lb $t1, OFS_Pico_m_sram_reg($t2)
andi $t4, $t1, 5
beqz $t4, 1f
nop
@ -288,8 +288,8 @@ m_read_neg1:
.endm
.macro m_read8_rom sect
lui $t0, %hi(Pico+0x22200)
lw $t0, %lo(Pico+0x22200)($t0) # rom
lui $t0, %hi(Pico+OFS_Pico_rom)
lw $t0, %lo(Pico+OFS_Pico_rom)($t0) # rom
xori $a0, 1
ins $a0, $0, 19, 13
.if \sect
@ -388,15 +388,15 @@ m_read8_misc_io:
nop
m_read8_misc_hwreg:
lui $v0, %hi(Pico+0x2220f)
lui $v0, %hi(Pico+OFS_Pico_m_hardware)
jr $ra
lb $v0, %lo(Pico+0x2220f)($v0)
lb $v0, %lo(Pico+OFS_Pico_m_hardware)($v0)
m_read8_misc_ioports:
lui $v0, %hi(Pico+0x22000)
lui $v0, %hi(PicoMem+0x22000)
ins $v0, $t0, 0, 5
jr $ra
lb $v0, %lo(Pico+0x22000)($v0)
lb $v0, %lo(PicoMem+0x22000)($v0)
m_read8_misc2:
lui $t0, 0xa1
@ -423,10 +423,10 @@ m_read8_z80_misc:
nop
m_read8_fake_ym2612:
lb $v0, %lo(Pico+0x22208)($t0) # Pico.m.rotate
lb $v0, %lo(Pico+OFS_Pico_m_rotate)($t0)
addiu $t1, $v0, 1
jr $ra
sb $t1, %lo(Pico+0x22208)($t0)
sb $t1, %lo(Pico+OFS_Pico_m_rotate)($t0)
# delay slot friendly
.macro m_read8_call16 funcname is_func_ptr=0
@ -468,15 +468,15 @@ m_read8_vdp:
or $t0, $t1
bnez $t0, m_read_null # invalid address
nop
j PicoVideoRead8
j PicoRead8_vdp
nop
m_read8_ram:
lui $t0, %hi(Pico)
lui $t0, %hi(PicoMem)
ins $t0, $a0, 0, 16
xori $t0, 1
jr $ra
lb $v0, %lo(Pico)($t0)
lb $v0, %lo(PicoMem)($t0)
m_read8_above_rom:
# might still be SRam (Micro Machines, HardBall '95)
@ -486,8 +486,8 @@ m_read8_above_rom:
# #############################################################################
.macro m_read16_rom sect
lui $t0, %hi(Pico+0x22200)
lw $t0, %lo(Pico+0x22200)($t0) # rom
lui $t0, %hi(Pico+OFS_Pico_rom)
lw $t0, %lo(Pico+OFS_Pico_rom)($t0) # rom
ins $a0, $0, 0, 1
ins $a0, $0, 19, 13
.if \sect
@ -583,11 +583,11 @@ m_read16_vdp:
nop
m_read16_ram:
lui $t0, %hi(Pico)
lui $t0, %hi(PicoMem)
ins $a0, $0, 0, 1
ins $t0, $a0, 0, 16
jr $ra
lh $v0, %lo(Pico)($t0)
lh $v0, %lo(PicoMem)($t0)
m_read16_above_rom:
# might still be SRam
@ -600,8 +600,8 @@ m_read16_above_rom:
# #############################################################################
.macro m_read32_rom sect
lui $t0, %hi(Pico+0x22200)
lw $t0, %lo(Pico+0x22200)($t0) # rom
lui $t0, %hi(Pico+OFS_Pico_rom)
lw $t0, %lo(Pico+OFS_Pico_rom)($t0) # rom
ins $a0, $0, 0, 1
ins $a0, $0, 19, 13
.if \sect
@ -723,11 +723,11 @@ m_read32_vdp:
m_read32_call16 PicoVideoRead
m_read32_ram:
lui $t0, %hi(Pico)
lui $t0, %hi(PicoMem)
ins $a0, $0, 0, 1
ins $t0, $a0, 0, 16
lh $v1, %lo(Pico)($t0)
lh $v0, %lo(Pico+2)($t0)
lh $v1, %lo(PicoMem)($t0)
lh $v0, %lo(PicoMem+2)($t0)
jr $ra
ins $v0, $v1, 16, 16
@ -771,11 +771,11 @@ PicoWriteRomHW_SSF2: # u32 a, u32 d
bnez $a0, pwr_banking
# sram register
lui $t0, %hi(Pico+0x22211)
lb $t1, %lo(Pico+0x22211)($t0) # Pico.m.sram_reg
lui $t0, %hi(Pico+OFS_Pico_m_sram_reg)
lb $t1, %lo(Pico+OFS_Pico_m_sram_reg)($t0) # Pico.m.sram_reg
ins $t1, $a1, 0, 2
jr $ra
sb $t1, %lo(Pico+0x22211)($t0)
sb $t1, %lo(Pico+OFS_Pico_m_sram_reg)($t0)
pwr_banking:
andi $a1, 0x1f

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