Compare commits

...
163 Commits
Author SHA1 Message Date
Luke Usher 04c608a21e bump version to v142 2025-02-05 13:28:51 +00:00
James Groth 8a75015d7e m32x: make PWM timer interrupt interval bits read-only from the MD side (#1813)
Per page 24 of the 32X hardware manual, the PWM timer interrupt interval
is read-only from the Mega Drive side.

This change fixes incorrect sound effects in Primal Rage. If the 68000
is allowed to write to these bits, it will change the PWM timer interval
from 1 to 16 during game boot, which breaks the game's PWM sound driver
code.

Primal Rage title screen audio before this change:

[primal-rage-before.webm](https://github.com/user-attachments/assets/0d8a33d1-22fb-4664-a802-00715541e67f)

After:

[primal-rage-after.webm](https://github.com/user-attachments/assets/87a3cdfe-85a4-45e7-8ea8-bc3e5bde4f7a)
2025-02-05 07:56:36 +00:00
Luke Usher 330a329abc desktop-ui: clear game browser search field when loading 2025-02-04 11:46:15 +00:00
Luke Usher a21f8c074c desktop-ui: add search to arcade game browser 2025-02-04 11:46:15 +00:00
jcm c899461cf1 build: More miscellaneous fixes (#1811)
Minor changes:

- Run CI for pushes to any branch, not just master. This is mostly
relevant for forks, where you will often want CI on WIP branches.
Releases still check that they are on the master branch and won't be
generated for other branches.

- The GCC `stringop-overflow` heuristic still seems to be buggy,
tripping in seemingly irrelevant areas, and in different areas depending
on toolchain/OS. Hence, just disable it for now; conforms with legacy
behavior.

- Fix a macro redefinition in the GTK CMake code

- Add a missing "included" source to the desktop-ui CMake code so it
shows up in IDEs

- `gersemi` formatting pass

Lastly:

Allow generating DWARF symbols in MSYS2/MinGW environments. This is
controlled by the cache variable `ARES_MINGW_USE_DWARF_SYMBOLS` (on by
default only for GCC, inoperable under MSVC/Clang-CL). This allows for
easier use of gdb or lldb for debugging on Windows. The support here is
considered incomplete but functional for debugging the main ares
executable.

In particular, we do not generate DWARF symbols on Windows in ares-deps,
so debugging dynamic dependency issues with gdb or lldb will require
self-compiling dependencies. DWARF symbols are also embedded and this PR
does not ship them with releases. The "primary" Windows clang build will
continue to use CodeView symbols so that releases may be debugged with
WinDbg, Visual Studio, etc.

I am not satisfied with this level of support, but I am also not sure
whether "full support" for two independent debugging symbol formats on
one platform is a reasonable thing or a good idea to maintain. For one
thing, ares-deps targets the MSVC ABI for portability, where DWARF
symbol availability is limited. Targeting the GNU ABI in ares-deps would
mean reconciling multiple independent components' dependence on libc++
that would eventually need to be linked together. This might
theoretically be possible but in any case is not undertaken here. Also
not undertaken is the extant PDB functionality for stripping into
separate files, bundling, copying to the rundir, etc.
2025-02-04 11:45:23 +00:00
Luke Usher 512b53f808 mia: update neo geo database 2025-02-03 13:48:45 +00:00
Luke Usher 2fb2da047c scripts: update-arcade-rom-db.sh should also import mame softwarelists too 2025-02-03 12:21:44 +00:00
Luke Usher cdbd9e0d2c mame2bml: better softwarelist export 2025-02-03 12:20:55 +00:00
Luke Usher 745e41a6ee desktop-ui: fix game browser not listing "neo geo" games. 2025-02-03 11:37:08 +00:00
Luke Usher ab40ecbb9b md: slight performance boost with loop free 32x timers 2025-02-03 10:07:05 +00:00
Luke Usher 72ead4d2a6 md: remove unnecessary pwm comment
was a note to self while testing
2025-02-03 10:07:05 +00:00
TascoDLX aef110f35d m32x+md fixes (#1807)
1. Revised pwm emulation, mostly to align with documentation. Not likely
to affect much except for rare edge cases. Also, added a dc filter to
prevent audio popping in certain situations (like window losing focus),
but pops on init are correct behavior. Fixes #937 by implementing
byte-wide fifo writes from the SH2 side.
2. Various fixups to 32x io access by the 68k. Fixes #1196 and missing
music in Brutal.
3. Follow-up to a previous PR: cram dots were not limited properly, and
line buffer adjustment was crashing 32x in certain cases (as reported in
the discord).
2025-02-03 07:45:59 +00:00
Giovanni Bajo e99c9c57b0 n64: fix a typo in ISViewer address range (#1806)
Added in 14786372. This basically prevented ROM size between 0x3f0'0000
and 0x3ff'0000 to work correctly in Ares.
2025-02-01 08:26:45 +00:00
Luke Usher 9c273abec3 md: better handle 32X PWM sample/clock rate changes 2025-01-31 19:53:54 +00:00
Luke Usher 6cc9f5a416 pce: reduce per-iteration conditional statements in psg
This also significantly increases performance
2025-01-31 14:40:52 +00:00
Luke Usher 69c20711fc pce: evaluate SuperGrafx check at power-on time in the VDP
This provides a significant performance boost pixel-accuracy mode
2025-01-31 14:40:52 +00:00
FitzRoyX 539aa9b7d6 cv, msx, myv: adjust overscan numbers (#1805)
active framing
2025-01-31 06:34:47 +00:00
FitzRoyX 5d7dbb7eed ms: adjust overscan numbers (#1803)
targeted 192 for ntsc and 224 for pal. Framing on top and sides is now
precise to active display. Sadly, only a few codemasters pal games
utilized 224.
2025-01-30 09:47:56 +00:00
FitzRoyX 6176287392 sg: adjust overscan numbers (#1804)
set to active display 256x192
2025-01-30 09:47:39 +00:00
FitzRoyX ce2e6f8c19 fc: adjust overscan numbers (#1801)
Overscan=off now shows active display centered and intact for both
regions. The pal ppu micromasking behavior was corrected (253 vs 254)
and commented out.

SMB2 EUR full frame

![smb2_e_fullframe](https://github.com/user-attachments/assets/3645d6b2-d97e-4f8a-865a-61464da01287)

before/after


![smb2before](https://github.com/user-attachments/assets/27fa1157-f715-4f92-9814-e1d13da2690a)
![ares-n](https://github.com/user-attachments/assets/fbed864b-2a05-4c0d-8a6b-8ce83d8a4684)

before/after

![Untitledggg](https://github.com/user-attachments/assets/03f41051-ca9b-4223-940d-d869745ff0a5)
![Untitledhhh](https://github.com/user-attachments/assets/dd761deb-6a34-4132-903c-433a36d22066)
2025-01-29 17:21:53 +00:00
Luke Usher 76ab41c69c sfc: fix screen offset after line-doubling work 2025-01-29 17:19:34 +00:00
jcm 928d76b0b5 CI: Use CI source directory when generating description (#1802)
Fixes the build. Verified to work here:
https://github.com/jcm93/ares/actions/runs/13033850846
2025-01-29 16:16:50 +00:00
jcm c1949d8eb5 CI: fix build (#1799)
Only include the commit subject in the release body rather than the
entire message.
2025-01-29 10:57:54 +00:00
Luke UsherandDarren Thompson 6946437115 Preliminary support for Aleck64 (#1758)
In its current form, all games that use standard Aleck64 hardware should
function correctly, using the current MAME romset at the time of writing
(0.273)

The following games are known to be working:

- Eleven Beat
- Hanabi de Doon! - Don-chan Puzzle
- Hi Pai Paradise
- Hi Pai Paradise 2
- Kurukuru Fever
- Mayjinsen 3
- Star Soldier: Vanishing Earth
- Super Real Mahjong VS
- Super Real Mahjong VS (Rev A)
- Tower & Shaft
- Vivid Dolls

The following games are known to be non-working:

- Magical Tetris Challenge (981009 Japan): Requires custom video
hardware: boots but unplayable.

Known Issues: 

- Games using EEPROM do not currently save their settings between
executions.|

---------

Co-authored-by: Darren Thompson <[email protected]>
2025-01-28 13:01:22 +00:00
invertegoandpng183 76a5f8e1da arm7tdmi: add instruction test harness (#1796)
Co-authored-by: png183 <[email protected]>
2025-01-28 12:45:24 +00:00
invertego bf9aae53d0 hiro: fix double character inputs in Windows HexEdit widget (#1798)
At some point it might be worth going through the list of widgets to
understand which ones require WM_KEYDOWN messages to be forwarded by
Application_keyboardProc. For the time being, it's clear the HexEdit
widget is not among them, so this change disables forwarding for that
widget type.

As an added bonus, this change also makes the number pad functional.
2025-01-28 12:45:13 +00:00
jcm 1a5559a24b build: Miscellaneous fixes (#1795)
- Fixes the nightly release so that the release body will contain the
latest commit message (only the first line). Tagged releases will now
also contain a description.
- Ignore a benign warning in sljit that was popping up in build
annotations.
- Fix a warning about a conflict in the `mia-ui` domain string on macOS.
2025-01-28 06:27:38 +00:00
jcm af5fa1a1c8 mia, desktop-ui: Add basic error handling to ROM loading (#1785)
> [!NOTE]
> Seeking testers on this to validate that errors appear correctly, are
accurate, and we didn't break anything.

### Description

Adds the `LoadResult` type, used to identify and propagate upwards
errors encountered when loading ROMs and systems.

Modifies the `mia` and `desktop-ui` load routines to use this type
instead of generic booleans, so that if we have a load failure, we can
propagate a precise and useful error to the user rather than a vague and
possibly mismatched one.

Currently the scope of the error handling is just `mia` and
`desktop-ui`; errors encountered when loading in `ares` itself are
currently generic "`otherError`"s. `LoadResult` is placed in
`mia/mia.hpp` so it is accessible to both `mia` and `desktop-ui`. If
LoadResult is added to ares loading in the future, the LoadResult type
may need to be moved.
2025-01-27 18:46:05 +00:00
Luke Usher 4c367fd32f sfc: don't line-double non-interlaced content 2025-01-27 14:49:22 +00:00
Luke Usher 2d714d1a9c md: don't line-double non-interlaced content 2025-01-27 14:33:42 +00:00
jcm 8dbd2135b7 CI: Refactor workflows (#1790)
This is a minor reorganization of the new CI to be more modular and use
more organized patterns. Rather than one large all-in-one workflow,
items are now split slightly into discrete parts. Namely, there is a now
a PR workflow called for PRs, and a push workflow called for pushes to
the master branch, which in turn call constituent workflows for builds
and releases.

This enables a few conveniences:

- Workflows are split into concurrency groups that will automatically
cancel themselves. For example, if a PR is pushed multiple times in
succession, CI will be automatically canceled for all but the most
recent push.

- Permissions are applied discretely and in a somewhat more organized
way. The PR workflow simply has the "read" permission, while the master
push workflow has the "write" permission.

While the existing all-in-one workflow was not insecure, it relied on
GitHub Actions failsafes (such as pulls from public forks not being
granted write permissions nor secrets) in order to work properly, which
has the side effect of making the workflow's logic somewhat more
difficult to understand.

- New workflows can hopefully be more easily created based on
constituent parts. For example, the PR flow simply executes "build",
while the push workflow simply executes "build" as well as "release".
Future workflows could, for example, "build" and then call a new "test"
workflow to execute the test harnesses using the built artifacts and
report results. This can now be done without requiring as much delicate
attention to the existing workflow logic.

Future work:

- Ideally our "build" workflow could be refactored into a composite
action rather than a workflow. This would enable it to use defines
created in the initial "pull" or "push" workflows more easily, allowing
us to cleanly separate, for example, codesigning-related steps that
install secrets on the build machine, from actual build steps/jobs.

> [!NOTE]
> This was tested on a local fork, but several minor changes were made,
so it's opened as a draft until it can be double checked that nothing
broke.
2025-01-27 10:04:33 +00:00
FitzRoyX c62e2a254c sfc: adjust overscan numbers (#1794)
These coord and offset numbers will hide all empty space (including
blanked active lines) without cropping any good pixels on the sides. The
output now matches old ares and bsnes. Whether the blanked lines should
be shown can be revisited later (most users have no idea what these are
and will hate them). SMW USA 1.0, SMW EUR 1.0, and SMW EUR 1.1 were used
for testing as each variant triggers each of the 3 modes and the game
draws border tiles all around.

Screenshots:

SMW USA 1.0


![smw_u10_overscan](https://github.com/user-attachments/assets/ab087adb-ccbf-4039-935c-876fab46baa8)


![smw_u10_xhideoverscan](https://github.com/user-attachments/assets/3a74120a-8468-4451-842e-495837fa4902)

SMW EUR 1.0


![smw_e10_overscan](https://github.com/user-attachments/assets/b790b84d-3632-434c-9307-8bc35555e995)


![smw_e10_xhideoverscan](https://github.com/user-attachments/assets/e11a179f-0775-4929-be19-3af24347e8c2)

SMW EUR 1.1


![smw_e11_overscan](https://github.com/user-attachments/assets/5ebdb315-3700-4ce4-9bd1-91077c3ff357)


![smw_e11_xhideoverscan](https://github.com/user-attachments/assets/ae07af5a-4acd-419f-b79f-bd4d07aeee63)
2025-01-27 07:00:03 +00:00
Giovanni Bajo dfcd7d4fce n64: fix gdb causing MIPS exception on attach (#1793)
Fixes #1778
2025-01-26 20:57:37 +00:00
Luke Usher fa1c21ba3d sfc: reduce overscan crop area slightly 2025-01-25 20:14:42 +00:00
曾耿森 a584782a86 fix: fix ppu scroll glitch bug (#1788)
Use open bus to set some parts of V
(glitch that occurs when writing to
$2000/$2005/$2006 on cycle 257)

Related issue #1235
2025-01-23 18:21:07 +00:00
jcm 6185edc43b ruby: Initialize sRGB option on Metal (#1789)
While looking at something else I noticed that we were not respecting
the stored value of the "Force sRGB" option on startup. As a result we
would always output in sRGB unless the user explicitly modified the
option during the session.
2025-01-22 19:15:34 +00:00
remutro 7772fdbf0a [MD/32X] Force PAL region when (PAL) or (Europe) are in ROM name (#1781)
There are numerous headers in Mega Drive & 32X games that are not
correct resulting in PAL games to run at 60Hz instead of 50Hz. This
corrects this issue by using the same technique the Atari 2600 core uses
which is to look for "(PAL)" or "(Europe)" in the ROM name which will
then force the game to run as a PAL game.

This also addresses the 32X game Shadow Squadron - Stellar Assault which
is supposed to be an NTSC-U and PAL game, but only has PAL in the header
so it could only run at 50Hz. This adds NTSC-U as an option (leaving PAL
as the default), but can be selected using the "Prefer US" boot option
so it can run at 60Hz.

Addresses issues: 
https://github.com/ares-emulator/ares/issues/1066
https://github.com/ares-emulator/ares/issues/1067

And yes, I'm aware I submitted an additional commit cause I spelled
Assault wrong in the comment, and managed to spell it wrong again in the
commit message. 🤦‍♂️
2025-01-19 17:22:06 +00:00
jcm fd8bcad5a1 CI: fix macOS CI PR runs (#1777)
Fix macOS CI on pull requests by persisting if we fail to import the
certificate (as expected). Notarization should expectedly fail as well
on pull requests, if it tries to run.

(Whether CI succeeds on this is the testing)
2025-01-19 10:09:06 +00:00
jcm da7a79b21e build: Remove redundant linking under gcc for test harnesses (#1779)
After https://github.com/ares-emulator/ares/pull/1774 the workaround for
the Windows variant of `main` being discarded early by `ld` is no longer
necessary.
2025-01-19 10:07:11 +00:00
invertego 639ebe6285 m68000: fix CHK instruction timing and flags (#1776) 2025-01-18 16:14:22 +00:00
invertego 9be2f9bb92 nall: move main/WinMain definition from .cpp to .hpp (#1774)
It's already expected that nall/main.hpp will only be included in a
single file, so we may as well define main at the same time. This allows
the console/Windows subsystem distinction to be controlled on a
per-target basis instead of being compiled into nall.

Targets that should always build as console applications now set a
CONSOLE variable in their CMakeLists.txt, overriding the cache variable
of the same name. The remaining targets can still be controlled at
configure time by passing -DCONSOLE=1, which will compile everything as
a console application.
2025-01-18 12:40:28 +00:00
TascoDLX ce71fff00c ym2612: fixing the bugs (#1775)
1. The cycle update order needed clean up, mostly to fix feedback.
2. Envelope update function was also reordered to avoid double update
issue.
3. LFO behavior was corrected (should apply proper attenuation when
disabled).
4. To avoid potential update issue, rate scaling was lightly refactored.
Avoids recalc of key scale factor and renames keyScale to rateScaling
(RS) for clarity.

Related issues: #1159, #1112
2025-01-18 12:39:40 +00:00
png183 a91b24acf1 arm7tdmi: write to rh after rl in multiply long instructions (#1773)
Tested on hardware, and verified that when rh and rl refer to the same
register, the write to rh overwrites the value written to rl.
2025-01-18 07:58:29 +00:00
png183 c5d316274a arm7tdmi: allow BX in Thumb mode with bit 7 set (#1772) 2025-01-17 13:41:34 +00:00
jcm 8444f52843 CI: Run new CI on pull requests (#1770)
Run the new CI on pull requests (and not just the old one) so we can
catch bugs and failures, take advantage of new inline annotations, etc.

Working on a slight refactor of CI in general to make it
better-organized, but seems worth PRing this first before that is
complete.
2025-01-16 09:12:25 +00:00
invertego d775c0968b m68000: fix linking error (#1771)
processor/m68000/m68000.cpp is already compiled into the ares static
library. It shouldn't be built directly by the m68000 test harness.
2025-01-16 09:11:31 +00:00
jcm c76b87cdb2 mia, desktop-ui: Emit error if database files not found (#1769)
For each emulator core with a `.bml` file in the Database folder
packaged with ares, this PR adds a separate check in their mia `load`
functions to verify that their database file exists on disk. If it does
not, we bail out of the loading process.

Meanwhile, in desktop-ui, if loading failed, we will now throw up an
error.

This PR stops short of adding fully robust error handling to the load
routines; the error message we throw up is generalized, and will appear
for anything that causes loading to fail, not just specifically database
files not being found. I think that the database files should be by far
the most common cause of load failure, so this seems OK to me for now,
but could certainly be improved in the future to provide more specific
errors. I obviously welcome feedback on how to handle any aspect of this
better.
2025-01-16 09:11:15 +00:00
invertego 2197df8cca m68000: add instruction test harness (#1767)
Add test harness for single step instruction tests located here:
https://github.com/SingleStepTests/m68000.git

See included scripts for cloning and running the tests.
2025-01-15 11:08:01 +00:00
invertego 324a192109 m68000: fix pc in privilege violation exception stack frame (#1768) 2025-01-15 11:05:57 +00:00
jcmandinvertego 4a9b77a5e1 build: macOS toolchain fixups (#1765)
Changes the regex used to determine our macOS SDK version to match on
Command Line Tools install paths and not just Xcode install paths, since
we do not require Xcode to build ares, just the Xcode Command Line
Tools.

Also fixes up how we handle the macOS deployment target.

(boring details below)

CMake is meant to transparently derive and pass appropriate compiler
options for our minimum deployment target. It does this via the
`CMAKE_OSX_DEPLOYMENT_TARGET` variable. This variable can be initialized
either by the project (which must happen before the `project()` call),
or else as part of the `project()` call, CMake will inherit it from the
`MACOSX_DEPLOYMENT_TARGET` environment variable, or else "compute it
based on the host platform" (whatever that means).

Our desired behavior is to set it to 10.13, except for local builds,
where we should respect the MACOSX_DEPLOYMENT_TARGET environment
variable (if it is set). This PR enables that behavior.

---------

Co-authored-by: invertego <[email protected]>
2025-01-14 13:43:19 +00:00
png183 a27c2a2b3a gba: stall CPU when accessing memory in use by PPU (#1763)
Since the timing of these stalls is dependent on PPU memory access
timings, this change should only impact the pixel accuracy setting.
2025-01-12 09:09:45 +00:00
jcm 34124fd1cc build: Switch invalid-offset diagnostic pragma to gcc (#1761)
Removes spurious warnings for invalid `offsetof` usage under GCC
(warnings have been previously determined to be benign for our usage).
2025-01-12 09:08:48 +00:00
jcm f6b58b076b ruby: Driver defaults fixups (#1762)
By default the SDL audio driver would initialize with a latency value of
0; this doesn't crash, but it ends up causing an unpleasant stuttering
and hitching, which is a bad default.

Also makes Metal the default driver on macOS.
2025-01-12 09:02:48 +00:00
jcm b4b026db28 build: Add local build option on Linux; compiler fixups (#1756)
> [!IMPORTANT]
> This alters default behavior for configuration on Linux that
maintainers should be aware of.

Introduces `ARES_BUILD_LOCAL` on Linux, enabled by default, that will
pass `-march=native` if enabled. Maintainers will probably want to
disable this. Also adds `ARES_ENABLE_MINIMUM_CPU`, `ON` by default, that
compiles with the previously enforced `x86-64-v2` minimum on x86_64.
Maintainers should do whatever they want with this option.

(@bsdcode @Mastergatto)

These changes are intended to give Linux users building from source a
better experience. Enabling x86-64-v2 compared to compiling without any
SSE functionality is a 10%+ performance loss locally in the N64 core,
and may be higher on actual x86_64 machines.

> [!NOTE]
> It is worth noting that even though we do not explicitly define a
minimum SSE functionality on arm64, in practice nall will still [define
`__SSE4_1__`](https://github.com/ares-emulator/ares/blob/e808d2c5ab5be91d3e1035063892e8c5115d25e2/nall/intrinsics.hpp#L232)
and take advantage of SIMD on that platform via sse2neon.

### Other changes

* Adds `-march=native` on macOS builds under the control of
`ARES_BUILD_LOCAL`, and fixes `ARES_BUILD_LOCAL` on Windows so that
`-march=native` is added under gcc and not just clang.

* Removes warning in the N64 core related to the issue caused by strict
aliasing under GCC.

* Fixed an issue where macOS would always generate for arm64 rather than
the host architecture.

* Ran a formatter pass that was previously missed on the CMake code, so
there are a couple miscellaneous formatting changes.
2025-01-11 18:11:56 +00:00
invertego 05898a6a04 sh2: fix recompiler regressions (#1760)
This change corrects two regressions introduced by my last change.

1. The purge() call in SH2::Cache::power() was, through a call to
Recompiler::invalidate(), accessing the pool array before it was
allocated.

    This purge call was erronous for two reasons:
    -   It was purging a single line, though it *appears* the intent was
        to purge the entire cache.
    -   According to the SH7604 manual, the cache is not initialized on
        reset.

    Therefore, I simply removed the call.

2. The size of the recompiler code cache for both of the two SH2s is now
halved to fit within the recently halved fixed code cache buffer. The
SH2 recompiler is good at reusing previously compiled blocks, so flushes
should not be especially common even with this reduced capacity.
2025-01-11 10:45:11 +00:00
Luke Usher 331c4956b0 desktop-ui: add support for cores that use DIP Switches 2025-01-09 11:57:57 +00:00
Luke Usher d6c42e59e4 desktop-ui: allow emulator interfaces a chance to modify port menus rather than hard-coding 2025-01-09 11:57:43 +00:00
Luke Usher 58661451ed mame2bml: exclude bios roms 2025-01-09 11:57:23 +00:00
invertego e808d2c5ab recompiler: code cache compaction (#1755)
- Reduce the code cache allocation from 128 MiB to 64 MiB. The CPU/RSP
split is now 63/1 instead of 64/64 (which was egregiously generous to
the RSP) so this should have little practical impact on cache flushes.
- Convert some larger static allocations to heap allocations to shrink
the ares executable's data section.

These changes increase the likelihood of the entire code cache being
within 128 MiB of the ares executable's text section, allowing for more
efficient branch encodings on ARM64 and better performance from the host
CPU's branch predictor.
2025-01-08 09:41:16 +00:00
jcm 445acba894 build: Allow non-strict aliasing and overflow optimizations (#1752)
Non-strict aliasing is found to resolve
https://github.com/ares-emulator/ares/issues/1737.

We also use signed integer overflow around ares, so we want to allow the
compiler to optimize for that if it wants to; essentially everywhere
ares runs is two's complement.

Couple quirks: Xcode has its own declaration for strict aliasing, so use
that. Clang-CL doesn't transparently accept `-fwrapv`, so it's passed
with `/clang:-fwrapv`.

`_ares_gcc_common_options` will eventually see more development to make
warnings consistent across platforms where possible.

(Fixes https://github.com/ares-emulator/ares/issues/1737)
2025-01-06 10:18:51 +00:00
remutro 07fa6bc265 Fix misc build warnings and vertical scroll on controller combo box (Windows) (#1753)
Cmake based builds don't disable as many checks as the old make files,
so there were a few new warnings clang was showing during the Windows
build about unreachable code in mia.cpp & desktop-ui.cpp that are now
fixed (it would fall through properly on other OSes). Note that there
are still two remaining warnings about unreachable code during the build
but this is within zstd included in libchdr so this needs to be
addressed upstream.

A user trying to compile ares made a single post in the ares Discord
channel about a warning they were receiving during the link phase about
an overflow. I've never seen the warning or remember anyone bringing it
up so I asked about OS/compiler (I know it was Linux flavored cause they
mentioned working on an AppImage) but they never responded. I think they
were using openSUSE, but it is interesting this wasn't flagged anywhere
else. We were assigning an enum value to a Color struct in
table-view-cell.cpp which wasn't correct, so this has been fixed.

Finally, SuperMikeMan100 pointed out that when the controller combobox
in Settings > Input didn't fit entirely on the screen, you couldn't
scroll to the bottom of the list (Windows issue). They also pointed out
the fix needed in combo-button.cpp which I've tested and have included
the fix for it here.
2025-01-06 07:37:23 +00:00
jcm 3e5ed40801 CI: fixups (#1754)
First commit stops notarizing the legacy build; for some reason
notarization currently
[fails](https://github.com/ares-emulator/ares/actions/runs/12626365618/job/35179407527)
only with the legacy build, despite us not having modified the legacy
workflow. In any case it seems fine to no longer notarize this artifact.

Second commit allows the new build CI to continue if the repository it
is being run on does not have macOS codesigning set up. This means CI
won't automatically fail on your fork if you do not have macOS
codesigning set up on your repository.
2025-01-06 07:34:12 +00:00
invertego 10b747c305 nall: add instruction_set to query cpu features (#1751)
Currently only implemented for x86.
2025-01-06 04:11:42 +00:00
jcm 2ed2ed34bc build: Add option to build cores as single compilation units (#1746)
Many parts of ares are compiled as a single translation unit in a "unity
build". Targets such as `hiro` and `ruby` directly compile only one
file, `hiro.cpp` or `ruby.cpp` (or `hiro.mm` and `ruby.mm` on macOS),
which `#include`s all other files beneath it in a branching fashion. By
contrast, in the `ares` target, each area of each core is generally
compiled as a separate translation unit, with lots of redundant
inclusion of common headers. This allows for faster "development cycle"
build times; if a small change to one part of the core is made, we do
not need to recompile the entire core.

Despite slower incremental build times, compiling each ares core instead
as a single translation unit has some benefits.

We can lower build times by a decent amount:

| Build | Build time (multiple units) | Build time (single unit) |
|-----------|-------------|-----|
| `ares-windows-x64` | 9m16s | 6m47s |
| `ares-windows-clang-cl-x64` | 11m3s | 8m23s |
| `ares-windows-clang-cl-arm64` | 12m29s | 9m20s |
| `ares-macos-universal` | 13m33s | 8m12s |

Not only that, but single-unit builds also seem to confer a minor
performance benefit, presumably due to more effective link-time
optimization.

On macOS arm64:

| Game (core) | VPS (multiple units) | VPS (single unit) |
|-----------|-------------|-----|
| Knuckles Chaotix (Mega Drive) | 101-102 | 108-109 |
| Snowboard Kids (N64) | 66-67 | 69-70 |

Last but not least, we can actually arrange for single-unit builds
without any code-level changes to existing ares source files. We can
simply add a `<core>.cpp` file for each core that includes each
'primary' `.cpp` file that would otherwise be directly compiled; due to
the magic of the `#pragma once` compiler directive, redundant header
inclusions are eliminated in the unity build, but compiling still works
normally if we are compile as multiple units.

Given that there were no significant issues adapting existing code to
compile this way, it seems worth considering adding this functionality.
It can disabled for default configurations transparently (to enable
faster incremental builds during development), but enabled on CI for
faster builds and a modest performance benefit.
2025-01-05 09:22:06 +00:00
jcm 41b61ee6d5 hiro: Fix various warnings and deprecations in Cocoa (#1748)
* Fix a bunch of miscellaneous name deprecations
* Fix deprecated modal file handling patterns; use the `URL` properties
rather than the ones for paths
* Remove the Gatekeeper bypass menu item
* While the idea here was quaint, it's very dated, the approach doesn't
work at all on modern macOS (and would be a significant exploit surface
if it did), and the functionality is somewhat outside the scope of the
ares application in the first place. It won't remove Gatekeeper
restrictions on ares itself, since if we're using the menu item, we've
already made it past Gatekeeper. Functionality to disable Gatekeeper in
general for other applications is, again, maybe nice in an abstract way,
but well outside our scope.
* Suppress OpenGL symbol resolver deprecation warnings
* Fix protocol warnings in `CocoaMenu` that revealed a mistaken design
pattern:
* We had both a protocol and an interface called `CocoaMenu`, and our
Cocoa hiro menu subclasses were declaring that they adopted the
`CocoaMenu` protocol, rather than what was almost certainly intended, to
be subclasses of `CocoaMenu` which would itself conform to the protocol
by virtue of being an `NSMenuItem`.
* In effect, this meant that each CocoaMenu subclass interface was
telling the compiler it wanted to reimplement the `NSObject` protocol
rather than be an `NSObject` subclass. This may have resulted in various
typical properties of `NSObject`s not being present, and various methods
(such as Accessibility) entirely not working.
2025-01-05 09:21:39 +00:00
jcmandJohn Tur a960aeef52 build: gcc improvements (#1750)
Linking was failing under MinGW gcc because of a link order issue
between `libares` and `mingw32`. Establishing a direct link relationship
between `desktop-ui` and `mingw32` means that our `WinMain` definition
will not be discarded by `ld` before it's needed.

We also here add a Linux gcc runner and a Windows gcc runner; these do
not upload artifacts, but will allow us to detect build failures on CI.

At the moment, gcc support in general under CMake will still rougher
edges than clang or MSVC support, but it is intended that building with
`gcc` and `ld` should always at least work, even if `clang` remains
recommended and achieves superior performance.

This PR also adds a warning in the N64 core to acknowledge
https://github.com/ares-emulator/ares/issues/1737 until that issue can
be fixed.

Co-authored-by: John Tur <[email protected]>
2025-01-05 07:24:54 +00:00
Giovanni Bajo 1eb0a1659a Update sse2neon.h (af7596e) (#1749)
Necessary to build the iQue branch on arm64
2025-01-05 00:01:49 +00:00
Adrian Siekierka c19a2ac1b2 ngp: more accurate refresh rate hint (#1742)
In practice that's ~59.95 Hz.
2025-01-02 00:46:37 +00:00
jcm 8642d35e5f CI: Fetch tags on checkout (again) (#1741)
`fetch-tags: true` only works within the specified fetch depth.

`fetch-depth: 0` fetches more than necessary, but seems to be the
simplest way to guarantee we actually fetch the latest release tag
needed by CI.

See also: https://github.com/actions/checkout/issues/338
2025-01-02 00:46:09 +00:00
jcm 80db392140 build: Disable OpenAL on Windows (#1744)
For various reasons, OpenAL on Windows is not supported. If we do manage
to find it and link against it, the build we produce is unlikely to work
outside of an MSYS2 command line environment, so we should just disable
it.

If we ever want OpenAL support on Windows, we would need to either
locate a version that depends only on Windows system libraries (i.e.
does not dynamically load libc++ or other MSYS2 libraries), or else
build and provide OpenAL ourselves as part of `ares-deps`.
2025-01-02 00:45:43 +00:00
jcm a2400ad43a CI: Fetch tags on checkout (#1740)
Should unbreak the new build.
2025-01-01 13:41:35 +00:00
TascoDLX e8cd9b3e04 md: vdp improvements, dots and stuff (#1739)
- Completes #1498 -- dots should be clearly visible in overscan areas
normally. If you notice odd dots appearing on top of games irregularly
(inbounds, non-overscan), please mention it. The Direct Color DMA demos
(https://gendev.spritesmind.net/forum/viewtopic.php?f=8&t=1203) should
be stable for the most part (note, they are very timing sensitive).
- VDPFIFOTesting rom should run without any failures. Previously,
16-FIFO Wait States was the only failed test.
- Both Titan Overdrive demos should run cleanly. There were a few minor
wrinkles that needed to be ironed out.
- Fixes #1075 -- there was a minor adjustment for a window edge case in
H32 mode. Unlikely to affect other games.
- Fixes #1061 -- looks pretty clean now.
- Fixes #626 -- I don't notice anything weird currently, just some minor
fringe in the left border, not visible when overscan is disabled.
- Review #1675 wrt md -- there are no parts of the active display area
that are currently cropped out. There was an unreported issue with Exo
Squad (E) that had clipped the topmost lines in PAL V30 mode (observed
on the copyright screen) but that has been fixed.
- Fixes an unreported bug in 32X PWM sound (right channel was missing),
typo from previous commit d7dfae7a7a.
2025-01-01 11:58:13 +00:00
jcm e04922c4d5 build: Finalize CMake merge (#1736)
* Remove version overrides from CMakePresets.json
* These were necessary for CI to run when CMake existed on the forked
branch, but *should* no longer be necessary
* Disable release flows for the legacy build
* Keep legacy builds running for the time being, but disable the release
flow so it does not conflict with the new CI
2025-01-01 10:22:22 +00:00
Mastergatto 69795d578a desktop-ui/presentation: Add an alternative path for loading shaders on Linux and BSD (#1738)
On some Linux and BSD distribution, Ares from the repositories may not
come with shaders preinstalled. Instead, these one may come from another
package, for example on Archlinux the package `libretro-shaders-slang`
installs the shaders in the following path:
`/usr/share/libretro/shaders/shaders_slang/` .

This will make Ares fail to load any shaders on these distro. So to fix
it, this PR adds the aforementioned location as another path to search
for, as a fallback.

I know, the two dots are a bit ugly, given that locate() normally
doesn't search for files or directories outside of those of
Ares...Ideally, locate() should be expanded to search the entire file
system, but I'm afraid the required changes may be a bit more far
reaching than expected.
2025-01-01 10:22:10 +00:00
8433666dc2 build: Build system overhaul (#1686)
This PR introduces a new CMake-based build system for ares.

Broadly, the goals of this build system are to:

* Modernize the build process somewhat, and make ares more approachable
for new developers
* Improve ares's dependency handling
* Expand and standardize platform/compiler/architecture support for ares
* Improve project code quality
* Improve build performance
* Lay groundwork for easier support of more platforms in the future

There are a few notable changes that this PR brings about. Briefly:

* Dynamic dependencies (librashader, MoltenVK, SDL, slang-shaders) are
no longer built in-tree
* Build system generation and building now take place as two separate
steps

Other notes:

* The legacy build system is deprecated, but is planned to still
function until such time as it is removed in a later PR

# New Features

* ares can now generate projects for Xcode and Visual Studio 17 2022.
Xcode is the recommended generator on macOS, supporting universal
binaries, advanced profiling and GPU debugging. Visual Studio projects
can be configured with either Clang-CL or MSVC, and may be generated for
either x86_64 or arm64.

* On macOS and Windows, dynamic dependencies are now built by
[ares-deps](https://github.com/jcm93/ares-deps) and fetched at
configure-time. This is to reduce build requirements for development,
define explicit versioning for dependencies, reduce build times
generally, and streamline CI workflows.

* Builds can now be configured through the default Windows command line
rather than requiring an MSYS2/MinGW shell.

* Ccache is also now universally supported to improve build performance.
Compile times should be further reduced with the addition of
precompilation of certain headers.

* A variety of other build system generators are now supported on all
platforms, including multi-configuration Ninja and applicable types of
Makefiles.

* Compiler diagnostic flags with clang have been standardized across all
platforms where possible[^1]. Currently, diagnostic flags have rough
parity with the old build system, but one goal of the new build system
is to introduce more strict compiler settings, to eliminate certain
classes of bugs and generally increase code quality.

# Supported Platforms

ARM64 and x86_64 architectures are officially supported across macOS,
Windows, Linux, and BSD[^1]. clang, Clang-CL, gcc, and MSVC are all
supported on applicable platforms. MSYS2/MinGW is supported along with
configuration and builds via the default Windows shell.

32-bit builds have not been tested.

# Current Status

Builds across all three of macOS, Windows, Linux, and BSD are generally
expected to work. Detailed build instructions can be found on the new
[ares wiki](https://github.com/ares-emulator/ares/wiki). CI workflows
are present and implemented but are still a work in progress. More
complete documentation is also a work in progress.

#### macOS

* Xcode, Ninja, Ninja Multi-Config, and Makefile generators are
functional
* Unlike Windows, multi-architecture builds are supported; pass
`-DCMAKE_OSX_ARCHITECTURES` as appropriate.
* Builds should generate a fully functional and relocatable app bundle
within the build directory, with relative rpaths; `install` rules are
placeholders.

#### Windows

* Visual Studio 17 2022, Ninja, Ninja Multi-Config, and Makefile
generators are functional
* Only single-architecture builds are currently supported
* Similarly to macOS, the build step generates a fully functional and
relocatable rundir with placeholder `install` commands.

#### Linux / BSD

* Unlike on macOS and Windows, it is required that the developer have
packages installed for libraries ares links against. A list of required
and optional libraries is found in the README.
* Build will output to a staging directory `rundir`; ares only uses
system libraries so this rundir should be fully relocatable
* `install` will perform a standard installation as CMake deems
appropriate for your distribution; you may pass the `--prefix` argument
as needed
* Maintainers may package as appropriate; a new Flatpak may be created
as part of this process, but has not yet

> [!IMPORTANT]
> These tasks should be completed before this PR moves out of the draft
state:
> 
> * ~~CI workflows~~ - incomplete
> * ~~BSD support~~
> * ~~Windows SDL added to ares-deps~~
> * ~~ares-deps should probably be migrated to the ares-emulator
organization~~
> * More documentation
> * Miscellaneous cleanup, fixing issues found in testing, incorporating
general feedback

Nevertheless, now that builds are functioning on all three platforms, I
wanted to get this PR out there in a draft state to solicit testing and
feedback, as well as to give Linux package maintainers a head start in
terms of packaging.

> [!NOTE]
> While the PR is in a draft state, there may be breaking changes,
things may temporarily stop functioning, commits may be squashed, etc.
Thank you for testing and please report any issues you encounter!

* More detailed documentation on the internals of the build system is
available
[here](https://github.com/jcm93/ares/blob/cmake/cmake/README.md).

### Miscellaneous changes/points

* .gitignore is reorganized
* [gersemi](https://github.com/BlankSpruce/gersemi) is used for CMake
formatting, hence the presence of a `.gersemirc` file
* SDL on Windows is now a dynamic dependency.
* macOS asset files are reworked into .xcassets archives
* new macOS local build script introduced
* CI will include debug symbols for easier crash debugging

[^1]: Indicates something that might not be finished yet, or is subject
to change

---------

Co-authored-by: invertego <[email protected]>
Co-authored-by: Stefan Schlosser <[email protected]>
Co-authored-by: John Tur <[email protected]>
2024-12-31 09:07:24 +00:00
png183 ecdce5e92b arm7tdmi, gba: lock bus during SWP instruction (#1729)
Hardware locks the bus during SWP instructions to ensure atomicity.

Also fixed an oversight from #1714 that broke serialization.
2024-12-29 21:46:36 +00:00
invertego 0b4fea8ce5 32x: fix instruction tracing with recompiler (#1734)
Fixes #1733
2024-12-29 21:46:00 +00:00
Luke Usher 5bcef4741a ps1: invalidate single blocks rather than entire pools (recompiler) 2024-12-18 17:56:14 +00:00
mote 3b18a3f808 fc: Save FDS disk when saving Famicom system (#1725)
This commit ensures that changes to the FDS disk get saved when the
Famicom system saves (similar to how the 64DD works already). Without
this, changes to the FDS disk were only written back to the pak in
FDS::disconnect, _after_ the save on unloading/exit or any periodic
autosaves.
2024-12-18 17:52:50 +00:00
Serina Huandjcm 7d327a2c8a Implement the hex editor widget for Cocoa and enable memory editor on macOS (#1723)
This PR adds the hex editor widget to Cocoa hiro and enables the memory
editor in Tools. The widget is a cell-based NSTableView with data source
the core hex editor widget and supports editing of memory (but not of
the encoded ANSI).

---------

Co-authored-by: jcm <[email protected]>
2024-12-17 05:18:14 +00:00
Giovanni Bajo 07bafb6a51 n64: improve VI timings and interrupts (#1716)
This commit implements correct VI timings using VI registers rather than
hardcoding the behavior for the default presets made by commercial
games. This makes Ares behaves correctly, timing-wise, also with non
standard timing like eg: the so-called PAL60 mode.

Moreover, it fixes VI interrupts in interlaced mode to happen on the
exact scanline they happen on the hardware, including known hardware
bugs.
2024-12-17 05:18:01 +00:00
png183 1bb1669b03 gba: cycle-based bitmap and affine backgrounds (#1714)
The pixel accuracy setting will now emulate the sub-pixel timing
behaviours for bitmap and affine backgrounds described in [fleroviux's
PPU
docs](https://github.com/nba-emu/hw-docs/blob/main/src/ppu/background.md).

This PR also splits the PPU into two separate libco threads: one for
rendering and one for raising IRQs and starting DMAs. This allows the
CPU and PPU to be run more asynchronously, which helps mitigate the
performance cost of finer-grained PPU emulation.
2024-12-17 05:17:47 +00:00
invertego a752b85d6f n64: step rsp dma during rsp execution (#1722)
Instead of advancing RSP DMA only after each CPU basic block, allow it
to run between each RSP block. This prevents the RSP from racing with
the DMAs it initiates in the event of a long running CPU block (which
can trigger multiple consecutive blocks of RSP execution).

This fixes hangs in Tarzan and possibly other games that use MusyX.

Another observable side effect of this change is that when the RSP is
halted, it no longer risks falling increasingly behind the CPU, because
ares will now step multiple times if needed instead of just once.
2024-12-15 10:46:15 +00:00
jcm a02c0f80de build: Remove brew make requirement for reals (#1720) 2024-12-14 09:17:50 +00:00
remutroandremutro 50ceb088ef Don't default to 'Text' column visibility being false in firmware window (#1721)
The "Type" column in the Settings > Firmware table view was being set to
false by default. As there is no visibility handling for columns in hiro
for Windows or Cocoa, this column would always be visible. But in the
hiro GTK table view definition (there is also a visibility
implementation for Qt) it did contain a function to disable/enable a
specific column so this column would be absent on Linux distros making
it look like there were duplicate entries in the table. This PR removes
removes the call setting visibility by default so that the column is
always visible.

Co-authored-by: remutro <remulationtro.gmail.com>
2024-12-14 09:17:33 +00:00
jcm 65618ce1e2 build: Remove macos-compat, establish appropriate minimum macOS (#1719)
* Remove `macos-compat`, since the macOS 12 runner is no longer in
GitHub Actions, so we can no longer target macOS 10.9
* Rename the macOS build to "macos-universal", reflecting the OS and
arch
* Don't install `make` via brew any more, since it isn't necessary
* Establish the macOS version minimum as 10.13
* 10.9 was not a proper target, because of `fstatat` usage, which isn't
available on macOS 10.9. On a code level, we may technically be
compatible with macOS 10.10, but because no available build environment
can target this macOS version, it makes no sense to support it without
being able to test it. Since we can deploy for macOS 10.13, just
establish this version as the minimum. If someone wants to compile
themselves for lower macOS versions, they should still be able to.
* Increment the macOS runner for the primary macOS build to macOS 15,
and the Xcode version to Xcode 16.1.
* Better to explicitly pick the macOS and Xcode version rather than
using `macos-latest` as the runner, even though they refer to the same
thing, just so that we have explicit versioning wherever possible.

Not tested; CI run needed.
2024-12-13 21:15:08 +00:00
remutro 4691971416 disable Apply button if driver changed then options updated before applying driver switch (#1712)
If you choose to select a new driver without pressing the Apply button,
and then go ahead and update related options for the currently loaded
driver then the combo box will revert to the currently loaded driver but
leave the Apply button enabled indicating the user has to do something
when they do not. This changes this behavior so that if options are
changed and the driver is reverted back to the current driver the Apply
button will be disabled again.
2024-12-07 13:55:21 +00:00
remutro 98d9eb7786 Bring back bsnes Pseudo Fullscreen Option (#1710)
Brings back the Pseudo Full Screen option present in bsnes as a
configurable hotkey.

I'm also including the type mistake pointed out for the colorWidthBleed
value someone pointed out so we don't lose track of it.
2024-12-06 11:04:07 +00:00
TascoDLX 431aba5a1a md: dma timing fixes (#1709)
Fixes test cases in the dma_speed_test rom.
1. "*VRAM TO ROM" is a dma load to a VRAM read target, which doesn't
have any effect. Though, for timing purposes, it's similar to a VRAM
write (1 byte access per slot) so fifo throughput is the limiting
factor.
2. A VDP refresh blocks bus access for 2 consecutive slots, slightly
affecting dma load transfer rates.
2024-12-06 00:24:07 +00:00
Luke Usher 78e5332361 sfc: use snprintf rather than sprintf in disassembler (-Wdeprecated-declarations) 2024-12-03 15:48:25 +00:00
jcm 687bfe8efc ares: move generated sources out of ares.hpp (#1704)
Random fix from CMake work.

Precompiled headers under CMake are currently buggy and unreliable on
Windows, largely because the precompiled `<ares/ares.hpp>` header
includes `<ares/resource/resource.hpp>`, which is generated by
`sourcery` as part of the build process.

While sourcery will almost never meaningfully change the contents of
this `resource.hpp` file, Windows may insert its own line endings
depending on the user's environment, and despite enforcing uniform line
endings as part of our `.gitattributes` file, some compilers will throw
a fit about the precompiled header being modified from underneath it.

Since the `resource.hpp` file is simple, short, and not included in that
many places, we can just refactor it out of `<ares/ares.hpp>` without
issue, and precompiled headers will work again regardless of system line
ending convention or environment.

Tested to build locally on macOS; CI run definitely recommended.
2024-12-02 12:48:55 +00:00
png183 7cc6d517a2 arm7tdmi, gba: more IRQ timing improvements (#1707)
- Check CPSR interrupt disable bit during decode stage
- Only update IRQ line at the start of memory accesses or idle cycles
2024-12-02 11:43:02 +00:00
png183 3bd385e4a8 gba: open bus improvements (#1706)
Fixes a few issues relating to open bus emulation:

- Accounts for cases where the last memory access was not an instruction
fetch
- For most memory regions, 8-bit and 16-bit accesses should be mirrored
along bus (except in IWRAM, where only part of the open bus value gets
overwritten, and the rest is carried over from the last IWRAM access)
- Open bus read alignment was not being respected in all regions
2024-11-28 03:23:51 +00:00
png183 de2d7d86c9 arm7tdmi, gba: IRQ timing improvements (#1702)
- Adds 1-cycle latch for IME register, similarly to IE and IF
- IRQ line is now checked between pipeline flush and instruction fetch
2024-11-21 11:02:48 +00:00
jcm a0d8ce25c5 nall: Use relative path for prefix (#1697)
Following up on #1688 and #1575; removes the ARES_PREFIX preprocessor
variable and its use in `prefixSharedData()` in favor of a relative
path.

Passing a preprocessor argument to the program to define an install
prefix, which is then used to locate application data, is awkward and
overall not an ideal approach. Wherever possible, ares should have the
same behavior on the same classes of OS. Further, if we are to cleanly
separate ares's build and install steps, we shouldn't be defining
anything related to install locations at build-time. After building
ares, it should be able to be installed wherever the user wishes without
any unexpected changes in behavior.

Following the standard paradigm here means that on *nix systems, the
prefix's data directory would be, relative to the executable, in
`../share/ares/`. Hence, define `prefixSharedData()` from #1688 to
return this relative path appended to the executable path (given by
nall's `Path::program()`), instead of doing the preprocessor prefix
hooplah.

Tested on aarch64 Fedora; made sure ares can still locate the database
and shaders.
2024-11-18 10:40:08 +00:00
Giovanni Bajo 557ecb5319 n64: correctly implement invalid SPECIAL opcodes in RSP (#1700)
All invalid opcodes in the SPECIAL range behave like "srlv rd, rs, rs".
Testrom: https://github.com/sauraen/rsp_inval_instrs

Thanks to Sauraen for the RE work
2024-11-18 10:39:07 +00:00
Tharo 8cc98f94ae n64: Fix 32-bit signed integer multiplication and division when the input operands are not sign-extended 32-bit values. (#1701)
Verified by the test ROM at
https://github.com/Thar0/N64-IntegerMulDiv-Test, see the readme there
for full details.

Note that the behavior of the div instruction is still not
well-understood when bits 31 and 63 of the divisor in rt are not equal.
These will still give incorrect results for now. The test ROM classifies
tests with such inputs in "failed emulations" since their behavior is
not understood well enough, while "failures" consists of tests with
inputs whose behavior is known and still failed.

Ares result before this patch:

![image](https://github.com/user-attachments/assets/f6e68e2c-b4be-4b38-8a5a-e7c2950817b1)

Hardware result (apologies for the poor video quality 😬)

![image](https://github.com/user-attachments/assets/51b5c5be-75cb-48a3-9828-9ed638722966)

Ares result after this patch:

![image](https://github.com/user-attachments/assets/6f19524b-eaa4-47c5-9e6a-1dd77ca400e4)
2024-11-18 10:38:47 +00:00
png183 7e5d749adc gba: implement pixel blend timings (#1695)
Separates `dac.run()` into two steps, with the lower layer being
processed two cycles after the upper layer. PRAM fetch timings should
now match [fleroviux's PPU
docs](https://github.com/nba-emu/hw-docs/blob/main/src/ppu/composite.md).
2024-11-15 11:08:47 +00:00
jcm 675d57b6fa nall: Fix data paths changes (#1694)
#1688 broke the build, and also did not actually perform one of the main
intended changes; reverting `sharedData()` to return "/usr/share/".

Second time's the charm!
2024-11-12 15:12:24 +00:00
jcm 28cfa89970 nall, desktop-ui: Account for other *nix data locations (#1688)
### Context

https://github.com/ares-emulator/ares/pull/1575 ended up defining the
`sharedData` directory on Unix-like systems as `~/.local/share` if a
build prefix was not defined. This is not exactly correct; the meaning
of a "shared data" directory on a Unix-like system is variously
`/usr/share`, `/usr/local/share`, or else the `share` directory of a
given install prefix.

### Changes

This PR allows us to respect normal Unix conventions while also
respecting the option to build and install with a given prefix. This is
done by defining two more functions in nall's `path`:
* `localSharedData()` for `/usr/local/share`
* `prefixSharedData()` for `${ARES_PREFIX}/share`

`sharedData()` is changed back to the old behavior and returns
`/usr/share`.

Then, the `locate` logic in desktop-ui (and uh, mia) is adjusted to now
search (in order):

1. the prefix's shared data if the prefix exists
2. local shared data
3. system shared data
2024-11-12 13:02:37 +00:00
Giovanni Bajo 8668f98fa5 Update parallel-rdp (#1691) 2024-11-09 13:51:34 +00:00
png183 8f772cdb01 gba: halt prefetcher when full (#1689)
Passes Alyosha's [test
ROM](https://github.com/alyosha-tas/gba-tests/blob/master/prefetcher/prefetcher_full_thumb.asm)
for timings in Thumb mode when the prefetcher is full.
2024-11-08 07:28:47 +00:00
Luke Usher 229e16df98 md: add support for QuackShot Starring Donald Duck (World) (Rev A)
This game has non-standard wiring; see comments.
2024-11-05 16:15:42 +00:00
Luke Usher 36290b9705 Merge commit '014d0130f534191ef36e727147264b84daaedb27' 2024-11-04 13:00:00 +00:00
Luke Usher 014d0130f5 Squashed 'thirdparty/slang-shaders/' changes from 263a54c414..7e2975e906
7e2975e906 Update crt-nobody shader (#645)
66de8e522b Sync to koko-aio 1.9.50 (#644)
4f3d214b31 Document #pragma include_optional (#643)

git-subtree-dir: thirdparty/slang-shaders
git-subtree-split: 7e2975e90632c93bc879707362469e6c9a3027b0
2024-11-04 12:59:37 +00:00
Luke Usher d6465d0daa Merge commit '802a902cd39324f874c9a7fa8ee1b2f0011ea432' 2024-11-04 12:59:23 +00:00
Luke Usher 802a902cd3 Squashed 'thirdparty/librashader/' changes from cbdbdafecd..82bfc2d576
82bfc2d576 deps: update deps
7d7536f9fd rt(wgpu): approximate clamp-to-border with clamp-to-edge if not supported
9039a7c040 reflect: use FastHashMap for linkinputs pass
d8e35d4374 preprocess: add a test for include_optional
76347f63ac preprocess: add support for pragma include_optional

git-subtree-dir: thirdparty/librashader
git-subtree-split: 82bfc2d576d4c1a90339dcfba6c0163d5345b9c3
2024-11-04 12:59:22 +00:00
Luke Usher 2bf4e28db5 Merge commit '14692993633944dc0edda0595cc4acbd56bd3581' 2024-11-04 12:59:18 +00:00
Luke Usher 1469299363 Squashed 'thirdparty/sljit/' changes from f6326087b3..666125ad64
666125ad64 Fix maximum offset prediction for jump operations

git-subtree-dir: thirdparty/sljit
git-subtree-split: 666125ad64fc694aafe6b816822ab446db14f5fe
2024-11-04 12:59:18 +00:00
Luke Usher 1e6e9fd36e ares v141 2024-11-04 10:19:26 +00:00
Fernap 8111bf3163 Fix for SA-1 side DMA to BWRAM banks 0x41+ (#1687)
DDA was incorrectly capped at 16 bits instead of 24, making DMAs to
BWRAM banks 0x41-43 be sent to the corresponding spot in 0x40 instead.
See [the corresponding bug in
bsnes](https://github.com/bsnes-emu/bsnes/issues/309) for some more
context.
2024-11-02 14:26:09 +00:00
jcm c287c1b225 build: macOS back-compatibility fixes (#1682)
While checking out minimum requirements for the new build system, found
a couple small issues worth fixing:

* librashader was not operable on systems pre-macOS 12 with a linker
issue; it can be resolved by setting a minimum deployment target; here
we do that by setting an environment variable on CI.
* While investigating this, I found that librashader's minimum required
macOS seems to be 10.15; this is because `glslang` seems to require
macOS 10.15.
* It wasn't possible to build the Metal driver because of the older SDK
lacking some definitions; however, we can fall back to the
`__MAC_OS_X_VERSION_MAX_ALLOWED` compile definition which we do here.
* Not sure if building on these older systems should really be
considered "supported", but since the fix here was simple enough it
seems fine to throw it in.

paraLLEl-RDP and MoltenVK seem to have [a lot of
issues](https://github.com/user-attachments/assets/088879a9-9153-4b05-a207-212cfac7f831)
on my older system's GeForce 650M. I was able to compile debug MoltenVK
locally, but Xcode GPU capture just hung, so I was unable to figure out
what was going on. Either a driver issue or a MoltenVK issue seems like
the probable culprit. In any case, performance wasn't really good enough
to make me want to investigate further. Other cores seem to work well.

Tested [on my fork's
CI](https://github.com/jcm93/ares/actions/runs/11554703214) to make sure
everything still works.
2024-10-28 15:30:08 +00:00
Giovanni Bajo 863593ed7f n64: remove call to epilogue function from the jit (#1663) 2024-10-28 11:44:11 +00:00
Giovanni Bajo c20d405006 n64: add unusual warning when using CACHE on uncached addresses (#1678)
The CACHE opcode does not work correctly when the specified virtual
address is in an uncached segment. The exact hardware behavior has not
been reversed yet (we know for instance that when doing cache
invalidation, some other cacheline is invalidated instead, but we do not
know the relation yet).

Nonetheless, the behavior is really obscure and all usages should be
considered bugs. Add a debug unusual warning for now (mainly to help
developers, as this is a known instance where Ares doesn't yet follow
hardware behavior).
2024-10-28 11:43:17 +00:00
png183 e1e1bedb2d gba: selectively synchronize CPU and APU, and add option to disable pixel accuracy (#1679)
Similarly to how the S-CPU and S-SMP are handled in the SFC core, it's
possible to run the GBA CPU and APU more asychronously as long as
synchronization is performed on FIFO or APU I/O accesses. From my
testing on Linux, this performs comparably to the performance profile
but without the accuracy downsides, so the performance/accuracy profiles
have been removed (the more accurate behaviour is now always used).

This PR also adds an option to disable pixel accuracy in the GBA core in
exchange for ~10-15% performance benefits, and makes some small PPU
timing improvements that were not feasible to implement in the
performance profile.
2024-10-28 11:43:07 +00:00
Chase Meadors 9f060c769b Allow arbitrary and possibly unaligned writes to RDRAM through gdb (#1639)
We want to allow arbitrary writes through the GDB server to the RDRAM
area. This was done in #1620, but that version has a subtle issue where
the server will still refuse to write or change writes that happen to be
of size `Byte|Half|Word|Dual` if the addressed is not aligned to that
size.
This PR fixes the issue by checking if the write is to RDRAM first,
allowing arbitrary and possibly unaligned writes. Otherwise, the write
is handled through the normal machinery where these issues may be
semantically important.
2024-10-27 15:14:30 +00:00
remutro e7f9af4bbd [N64] allow for pak swapping on controller port 1 (#1672)
This pull request allows for all pak swapping on controller port 1 only.
It also enables support for the transfer pak for the 64DD which was
previously missing.

It is being added for port 1 only now because there is additional work
to manage all the different saves, and gameboy games/saves with the
transfer pak which is a larger effort, and Luke is currently looking
into modifying settings in a more complete manner. So other ports can be
added later. For most people, being able to swap for the first
controller is likely good enough.

This pull request doesn't change any of the current initialization logic
regarding default pak selection that already existed.
2024-10-26 07:53:52 +01:00
jcm 65c34c2ea4 nall: Namespace noinline macro (#1674)
This is a change spun off from continuing build system work.

There, we've found that precompiling the `ares/ares.hpp` header can
speed up compile times for the emulator cores by 30-35%. Doing so,
however, leads to a few collisions:

* Several files in parallel-rdp use the `Hash` type, which variously
resolves to a `Hash` in its own namespace as well as nall's namespace.
* Also in the N64 core, nall's `noinline` macro conflicts with similar
definitions present in `xxhash`.

For parallel-rdp, we can simply skip precompiled headers for the
conflicting files; parallel-rdp does not use anything in the
`ares/ares.hpp` header, so including it there is unnecessary anyway.

This change resolves the second set of collisions by putting nall's
noinline preprocessor macro into its own namespace.

There are many macros remaining that are not namespaced. I did not
proceed in namespacing them for this PR, because there are a lot of
them, and it would be a fairly significant code style change that
probably merits further discussion (not to mention, it will be a decent
amount of work). However, in this instance, there is (or will be) a
material benefit that probably trumps the minor style issue.
2024-10-26 07:53:36 +01:00
png183 9babe6a02b gba: OBJ timing improvements (#1676)
Implements a couple improvements to OBJ-related timings:

- OBJs are now rendered one scanline in advance, as on hardware
- OBJ palette RAM accesses are now performed in `PPU::Objects::run`
rather than `PPU::Objects::scanline`, bringing OBJ PRAM access timings
closer to matching hardware
2024-10-26 07:53:20 +01:00
png183 7e5292cd16 gba: horizontal mosaic fixes (#1669)
Addresses an off-by-one error with BG mosaic, and fixes an oversight in
how OBJ mosaic was handled at x=0.
2024-10-22 11:32:42 +01:00
remutro a8274cd127 [N64] Add support for 40 Winks (Aftermarket) and support for additional supported regions (#1666)
40 Winks was released aftermarket on physical media, and support has
been added for this (does NOT include prototypes). The US version was
tested, but was unable to test the EU release (game Id and pak options
should be the same and should theoretically work).

Additionally, looks like ares was missing some region descriptions, so
these have been added as well based on info located at:
https://n64brew.dev/wiki/ROM_Header#Advanced_Homebrew_ROM_Header
2024-10-18 11:11:07 +01:00
Giovanni Bajo d99b0a3725 n64: use different GDB signals for different exceptions (#1667)
When debugging homebrew with gdb, it might be annoying if gdb stops at
exceptions that are correctly handled by the running application. This
is a bit hard to know so, besides providing some (debatable) default, we
need a way to selectively ignore specific exceptions.

This commit generates different GDB signals for different families of
exceptions. The mapping between MIPS exceptions and UNIX signals is
completely arbitrary; it tries to "sort of" match the meaning of the
exception where possible, and otherwise just use a random signal.

The GDB client can configure which signals should be logged, which
should cause the application to stop, and which should be ignored, using
the "handle" command.

By default, we want to ignore exceptions generated by interrupts (as
those are normally handled by the application) and those handled by the
operating system (like the COP1 exception which both libultra and
libdragon use to speed up context switching). To do so, we assign to
them signals that are ignored by default by gdb (SIGWINCH and SIGURG
respectively).
2024-10-16 06:32:31 +01:00
Luke Usher e43f3f75f7 add ymfm to update-subtrees script 2024-10-08 11:48:21 +01:00
Luke Usher f894a85253 Merge commit '09fbcc4e65efe68eefc6d4f502fd92cb9ee310b4' 2024-10-08 11:33:31 +01:00
Luke Usher 09fbcc4e65 Squashed 'thirdparty/ymfm/' changes from d641a80631..d334ab1a95
d334ab1a95 Fix left-shift signed overflows (UB) (#62)
434e793dc4 Assert that only valid timer numbers are passed to engine_timer_expired().
16e1d4281a Use snprintf instead of sprintf to fix #59. Use std::array for operators to remove the need for array_size.
4e654a3e8f Add virtual destructors to all base abstract classes, to prevent memory leaks (#55)
1a5cc66cb6 Keyon all ops on CSM mode (#56)

git-subtree-dir: thirdparty/ymfm
git-subtree-split: d334ab1a957351ce2a0aa2777b8c704664be3189
2024-10-08 11:33:31 +01:00
Luke Usher 38dd6defa9 Squashed 'thirdparty/slang-shaders/' changes from ec1b855638..263a54c414
263a54c414 Update crt-ntsc-sharp presets (#642)

git-subtree-dir: thirdparty/slang-shaders
git-subtree-split: 263a54c414681b45fd9428143a8320f4024a99ab
2024-10-08 11:33:15 +01:00
Luke Usher 73d90e6e7c Merge commit '38dd6defa99bb03aa5e4dc2fc1f492b2e85aa10c' 2024-10-08 11:33:15 +01:00
Luke Usher b2175473f0 Squashed 'thirdparty/librashader/' changes from 4abd48eb24..cbdbdafecd
cbdbdafecd chore: Release
ffcb8ba1d1 doc: Update BROKEN_SHADERS.md
941275199b build: unpin cc
525c311844 cli: allow raw-id for spirv output
2fe66d958f reflect: put vars to end with running link pass to fix naga ordering
ed8bf637a9 cli: size_of not in prelude
7555bb9024 build: make librashader-reflect features-table more consistent
562e1e5f18 doc(msrv): bump msrv to 1.78
13b44e1639 cargo: revert lockfile version
240aae1bcf chore: Release
95a489ee12 cli(render): allow specifying output dimensions

git-subtree-dir: thirdparty/librashader
git-subtree-split: cbdbdafecdfd6113ef1cdc15e0a4140b46420f0b
2024-10-08 11:33:01 +01:00
Luke Usher 030488aba7 Merge commit 'b2175473f0476248724ba73bb80b71a1c669797d' 2024-10-08 11:33:01 +01:00
Luke Usher bc2a54800f fix sljit after update 2024-10-05 12:56:24 +01:00
Stefan Schlosser 6e182d8542 thirdparty/librashader: activate runtimes in librashader_ld.h 2024-10-05 12:37:24 +01:00
jcm 38f64fa70c ruby/metal: Update to librashader ABI 2 (#1)
We elect to just remove all usage of libra_viewport_t for Metal, since the current rendering path conforms better to recommended Metal patterns than passing the drawable texture directly to librashader would.
2024-10-05 12:34:08 +01:00
Stefan Schlosser 7eb1b28671 ruby/opengl: adapt to librashader ABI 2
The libra_gl_init_context function has been removed. The OpenGL loader used to
create the filter chain, previously passed to libra_gl_init_context, is now
passed as a parameter to the libra_gl_filter_chain_create function.

The libra_output_framebuffer_gl_t and libra_source_image_gl_t structs have been
replaced with libra_image_gl_t.

The position of the viewport parameter in libra_gl_filter_chain_frame has moved
to after the output parameter, and its type has changed from libra_viewport_t to
libra_viewport_t *.

In order to retain the behaviour in ABI 1, output holds the width and height of
the previously used viewport and the viewport itself is removed and replaced
with NULL in the call to _libra.gl_filter_chain_frame.
2024-10-05 12:34:01 +01:00
Stefan Schlosser 42c16831b7 thirdparty/librashader: update SONAME of librashader.so in build-librashader.sh 2024-10-05 12:33:31 +01:00
Luke Usher 5982fa8ae3 Squashed 'thirdparty/slang-shaders/' changes from 693c632bdd..ec1b855638
ec1b855638 Add RF-nes presets to crt-royale-fast folder (#640)
a8e35920c5 Update crt-geom.slang (#639)
901441a496 Update crt-royale-fast and several presets (#638)
33876b3578 ensure testPattern() always has a return condition
5ab3c76109 update patchy-ntsc shaders and presets (#637)
edd2dd3f77 fix some errors identified by librashader scan (#636)
630fe655fe fix mudlord-pal-vhs
49c77cab02 remove another conflicting pass from preset
e1f7c6cc0e remove broken/unused pass from preset
0e29397870 add small, colored border shader (#635)
4ef678cab0 fix bad path
bd0ea94fc8 fix/update glow-trails shaders and presets (#634)
0dd9204791 Update crt-royale-fast and its presets (#633)
24f9468e2e Add crt-royale-pvm-shmup preset (#632)
0a305b879e Update crt-royale-fast and add new presets (#631)
1b2ad364b7 Add edgeNpixels shader (#630)
b9e012f25c Patchy NTSC - Bunch of last minute improvements (#629)
4cf85d3147 New NTSC shader by PlainOldPants (#627)
ef68606c0e Add edge1pixel shader (#628)
0cededfa7f ntsc-simple update to glsl version (#626)
811bb31cdb port tiny_ntsc (#625)
ef702029d8 Fix color clipping in crt-hyllian (#624)
b6b55c3995 Update crt-hyllian (#623)
26e9882eb2 Update crt-hyllian (#622)
b3d795acb9 Add crt-royale-ntsc-composite-fast preset (#620)
111fcedc3b Add crt-royale-fast shaders (#619)
b327343b77 Fix a 7-year old bug in crt-royale-bloom-approx.h (#618)
679a3321c1 Update crt-geom-mini.slang (#617)
f65a4bce69 Sync to koko-aio 1.9.30 (#616)
7d6751a07c update crt-guest to latest (#614)
05a41341be Fix input TF bug & large refactoring; Add box filter AA (#613)
5e702cfdc6 Added flat trinitron TV filters (#611)
1c6f2cd834 Add zfast_crt_geo shader (#612)
46b96cbd39 update crt-geom-mini to glsl version (#610)
959de2bb2e Reverted texture optimizations as they are breaking rendering. (#609)
23f90e3b27 crt-geom-mini update from glsl, crt-pocket fix clamp error (#607)
3796d44482 Update geom.slang (#606)
89dfd9bbd0 Add Geom shader (#605)

git-subtree-dir: thirdparty/slang-shaders
git-subtree-split: ec1b8556388317258376467c1561ecb91a06a466
2024-10-05 12:32:59 +01:00
Luke Usher 5f435345f1 Merge commit '5982fa8ae35f801150b06b8db273b628ea0f7cd9' 2024-10-05 12:32:59 +01:00
Luke Usher 8343f8136c Merge commit '4dcba4224027a101e7d4e21d23ada1f08e7baf2c' 2024-10-05 12:32:27 +01:00
Luke Usher 4dcba42240 Squashed 'thirdparty/librashader/' changes from fff80df5a0..4abd48eb24
4abd48eb24 capi(presets): support `d3d9_hlsl` VID-DRV
0007bd6d98 doc: update preset_ctx_set_runtime doc
72c72dafa0 capi(d3d12): remove unintentional IMAGE_TYPE infix for LIBRA_D3D12_IMAGE_TYPE
0fde712f3c doc: update librashader::reflect docs
2323b18710 capi(ld): add `LIBRA_RUNTIME_D3D9` define commented out
5978f95f76 reflect: make `ShaderPassArtifact` simpler as `PassResource` already includes the source data
3ee5e66c0d presets: make naming more consistent
f189468f6d ci: don't build cli for windows 7
fc47fb4c5a doc: typo
fc7739d9ab ci: update github actions
4a8a9ee444 chore: Release
756cbe63d9 cli: fix cli Cargo.toml
796b03b42b test: rework tests to work with ShaderPresetPack
742a1c8658 dep: update glslang
7c03a7e3fe doc(pack): reword doc on `ShaderPresetPack`
4ba6effc2f rt(mtl): fix test
32c99d9f4a rt: implement filter chain loading in terms of pack
75b70cc0e6 cli: add `pack` command to create a preset pack
828464c351 rt(image): helper to load image from shaderpack `TextureBuffer`
c19593e289 pack: implement shader pack library to preload resources from disk
1bbbd784d8 preset: make ShaderPassConfig and TextureConfig type aliases to PathReference
4273a833e8 pack: add librashader-pack
f14f45b3b1 rt: separate out meta information for textures
859d16e64e rt: separate out meta information to its own struct
b395b94a40 doc(abi2): add migration details for `libra_source_image_d3d12_t` layout
90a9ee754d doc: fix migration api typo
34b50059ca doc(d3d12,vk): clear up language for barriers
7a13136f9a capi(d3d12): allow d3d12 to optionally use a resource handle with chain-managed descriptors
0cb3880d7f rt(d3d12): allow construction of D3D12InputImage without a descriptor handle
c526b7043a capi(d3d12): change the layout so that descriptor is first in libra_source_image_d3d12_t
33d95ac399 rt(d3d12): allow creating input view without a CPU handle
40691cc406 rt(d3d12): allow creating output view from a resource ref
3c20c83bc9 rt(d3d12): use InterfaceRef for D3D12InputImage to avoid refcount for input image
b123f63a6e doc(reflect): fix link
4285ad2bd1 rt(d3d12): allow a pipeline to be available for multiple formats without recompilation
c57e502b78 rt(d3d12): make images with OwnedFramebuffer provenance use ManuallyDrop
7edff0ae35 rt(d3d12): allow manually specifying the strategy to get a manuallydrop for luts
dedde05c83 rt(d3d12): move update subresources to lut
7d483f2e08 rt(d3d9): take viewport by reference to avoid AddRef/Release
7b7fd99b92 rt(d3d11): take viewport by reference to avoid AddRef/Release
28931ae50a rt(d3d12): update d3d12-descriptor-heap
2fe7702957 rt(d3d11): avoid QueryInterface in GetSize
a5c8fcf4f8 doc: missing period
629070ea2f ci: build cli
da53c3df59 cli(render): make frame inclusive to ensure correct feedback and history behaviour
84e78f4e48 cli(render): add ability to specify frame options
91f8089277 cli(render): add ability to specify params and passes enabled
3993f57271 doc(cli): document CLI
55ff7a93f2 cli: rename librashader-test -> librashader-cli
227757a221 cli: parse transpile versions
a72a593029 reflect: allow indexed and non-indexed semantics to be serialized and deserialized as strings
1537c1bcd7 cli: ensure shaders are validated before compile
5573f13227 test: add CLI with multiple functions
bac09ad2a3 reflect: allow validation of shaders without reflecting against semantics
31ece05246 reflect: allow more reflection objects to be serializable
5ede061975 preprocess: allow shadersource to be serializable with serde
1676150858 presets: allow presets to be serializable with serde
eeda0d02d0 test: make RenderTest trait object safe
f7a938a00d deps: update dependencies
6394b28d40 deps: update dependencies
443fa20d22 test: clean up imports and features
5c726efe21 test(d3d12): Add D3D12 render test
d33c2a84b2 test(d3d9): Add Direct3D 9 render test
5a35a2bd1e test(render): reenable cache
41034330a7 test(mtl): Add Metal render test
a7836923d7 test: split test harnesses into features
20039b9347 test: abstract test framework
799d409ddb test(gl): Add OpenGL render test
79513a301e test(vk): Add Vulkan render test
6de2de8d12 test(wgpu): Add WGPU render test
2904a2ac10 test(d3d11): Add D3D11 triangle test to image
341fbceb82 rt(d3d12): derive clone on D3D12InputImage
c54747d398 deps: update dependencies
3888b56c83 rt(d3d9): accept input image by reference
b0df631651 rt(d3d9): load LUTS as BGRA8
dbfa822f7c rt(d3d9): disable alpha blending
e7fe96520e rt(gl): ensure framebuffers are bound
97ad0d64bf rt(gl): make FilterChain::load_from argument order consistent with other runtimes
feaebc5f44 fmt(gl): cargo fmt
ef35e2a620 presets: rename to_hashmap -> into_hashmap
987e967269 doc(capi): add error doc for infallible error
c3469520f9 examples(d3d11): fix d3d11 examples
45b98a2bdd rt(gl): use array_init instead of manually doing it with MaybeUninit
2ee9eca854 ci: ignore .DS_Store
59937aced5 fmt: cargo fmt
e4eed34c10 capi: const qualify chain in `_filter_chain_get_param` and `_filter_chain_get_active_pass_count`"
7abd679bd7 doc: add migration docs
41353ac9c4 rt(gl): remove need for explicit external FBO object
4d790e7a7b doc: update ABI versions in version.rs and readme
aeb0a16cfb rt(vk): allow specifying the queue to use
16108838b1 rt(d3d11): remove unneeded transmutes
7cfbca7755 rt(wgpu): remove unnecessary output move
8467e5cd97 rt(mtl): remove unnecessary output move
1e33b4cc03 capi: make viewport optional, defaulting to a viewport that is the entire size of the render target
eb53699590 capi(include): update headers
0cbf8024a7 build: update soname
7e354a56a1 capi: upgrade cbindgen to fix syn bug
0a87bcc657 rt: respect viewport extents when rendering
f0a7970b44 rt: add viewport extent separate from output texture dimensions
e7e6ed8fb8 capi: remove _internal_alloc from libra_preset_param_list_t
61fdaeea14 capi(gl): update to take opengl context in constructor
2552d4321b capi(gl): set output in libra_output_image_gl_t, not viewport
eaf939c861 capi(vk): set output in libra_output_image_vk_t, not viewport
14abb0362b capi(d3d12): set output in libra_output_image_d3d12_t, not viewport
e064f8d0be capi(d3d12): remove ignored fields from libra_source_image_d3d12_t
f18c22a95a capi(d3d11): take ManuallyDrop<ID3D11ShaderResourceView> directly in libra_d3d11_filter_chain_t
763c05755d rt: mark error types as non_exhaustive
e6d23f1d8f doc: update opengl example
2f9df143cf deps: consolidate and update dependencies
1bdadaa449 rt(gl): port to OpenGL runtime to glow
77b957bf5e reflect: stop adding null bytes to uniform names
1e0727f89d chore: Release
60d2c3f177 chore: Release
72a98272f3 doc(capi): document all C API members
7d0b135710 rt(mtl): remove unused 'pass lifetime
4ba5aefafc capi: don't export wrap_ok macro
6edfaed91f test: update slang-shaders
cd877d7883 build: respect CARGO env in build script
d56d92ea0f test: update slang-shaders
f49e3b58d8 doc(capi): fix rotation integer docs
1f4f1b6c12 capi: Fix Metal error message, function header
57f2dabf0c reflect: fix `CurrentSubFrame` being parsed as `TotalSubFrames`
81840a9e9c reflect: insert alias semantics for shader name through pragma
87e0405675 presets: properly trim shader name if given through pragma
e0c97f77b4 build: nicer build script messages
6e60dd6fa0 test: update slang-shaders
d55d0e4839 rt(mtl): use f32::MAX for lodMaxClamp
6cdd9247de presets: trim aliases and shader parameter names
cbe6510f76 preprocess: the step argument is optional according to slang-shaders spec
d6f8950bdc rt: only draw last pass twice if the last pass is needed as feedback
0fe5bbd57b rt: do reflection to see if the final pass is needed as feedback
eace595ebb chore: Release
66561ad2ed doc: fix header image
05d48841ad doc: update docs for stable build instructions
927740433c build: remove unneeded image dependency
316e92dc09 build: allow building stable with --stable flag
e930f90a9c capi: allow building on stable by gating #[doc] comments
2f988d5b1d rt: add stable feature to build ShaderPassArtifacts via Box<dyn CompileReflectShader>
e0a5c90103 reflect: implement stable FromCompilation
4cc3c875bf reflect: allow compilation of boxed trait objects
805854b94b reflect: simplify FromCompilation output signature
c291d9d85f capi: remove dependency on `try_blocks`
8b2ff57ee8 reflect: replace `let_chains` with `Option::filter`
3d9139b4e0 rt(d3d11): replace `let_chains` with stable alternatives
b432a1e02d rt(d3d12): replace `let_chains` with stable alternatives
ab9ab6fe68 rt(gl): use `Option::filter` instead of `let_chains`
0ba4c482b3 rt(vk): use `Option::filter` instead of `let_chains`
57f9a13ee7 rt(wgpu): use `Option::filter` instead of `let_chains`
2661effab4 chore: Release
02288554b9 rt(mtl): fix history buffer off-by-one by buffering the history read.
98d8d91c66 capi: undo const qualification of chain in `_filter_chain_get_param` and `_filter_chain_get_active_pass_count`
6f5b342c1b build: fix dev-dependencies on non-apple
bec0482513 ci: trigger ci
e24beede0b rt(mtl): draw final pass to output targets
22b2118e97 rt(mtl): don't resize if the requested format differs from optimal format
856f69113d rt(mtl): don't make mipmapper for history if not needed
477d0ae67c rt(wgpu): draw final pass to output targets
e68da7b984 rt(gl): draw final pass to output targets
666588ef0d rt(vk): draw final pass to output targets
336f540ce9 rt(d3d9): draw final pass to output targets
894d19eb81 rt(d3d12): draw final pass to output targets
1bf5d7efca rt(d3d11): draw final pass to output targets
c9205bc922 rt(mtl): remove internal_frame_count
cebc7a939a rt(mtl): fix faulty history but only copying one mipmap slice of texture
fe48fd03a5 test(mtl): update the metal test
50580cfc3b chore: Release
075a2981e1 rt(gl): fix `glShaderSource` going past the buffer
a7dd40a79f ci: allow c_str_literals to maintain a lower MSRV
fd8d6f6ab8 chore: Release
c5fdffa6aa dep: update cargo.lock
090e268c4a doc: improve docs
8856a78eb8 api: expose `FastHashMap` and `ShortString`
ec3add1616 rt(params): rename get_parameter -> parameter_value
f83fd1e98f ci: debug is broken on windows 7
c3033cfbbf reflect: port to spirv-cross2
820fb69328 reflect: remove get_prefix from get_texture_semantic/get_unique_semantic
c9a6411394 deps: consolidate and update dependencies
40a56bf165 reflect/preprocess/presets: use SmallString where it makes sense
c447e40583 rt: redesign parameters to be thread-safe across FFI using arcswap and atomicusize
ae76bf9cc1 rt(d3d12): pull out descriptor heap implementation into its own crate
e934f175ef rt(d3d12): stop leaking transition barriers
2e7c3b3273 rt(d3d12): use gpu_allocator instead of CreateCommittedResource
e90c27ebbd rt(vk): use manuallydrop for VulkanBuffer rather than Option
8fb5d48a1e chore: Release
b7fd3bc507 runtime: fix image swizzle for remainder
af05cc5bd8 ci: build for windows 7
2f0a3356d9 rel([email protected]): doc fix
0efaf2b8a0 doc: fix docsrs build on macos
436d1fe3cd chore: Release
0ce11bac71 doc: promote d3d9 to secondary support
bc269c270c rt(d3d9): remove backtrace from Direct3DError
db3d5d05a6 presets: use crate for extract_if with fully qualified syntax to avoid name collision with unstable std
1957f576ca reflect: further improve link i/o pass by ensuring that the output SPIR-V is valid according to Vulkan 1.0 semantics
5560c1ed09 runtime: use a more efficient swizzling implementation without array_chunks_mut
f8c055524b doc(readme): document shader pre-linkage
fee92113f1 ci: remove PR full test
45c3c876f4 reflect: remove explicit compile function in favour of TryFrom
28f5674a80 presets: remove rustc 1.74 compatibility
bffad12ea2 doc(presets): add docstring for ContextItem::key
321e30a0f1 capi: extend config_struct macro to handle overrides
9b40c10466 reflect: improve inout link algorithm
cd14bca23a Revert "reflect: improve inout link algorithm"
1ac78695c6 reflect: improve inout link algorithm
d1e49b7eb4 rt(d3d9): search "global" namespace for register assignments
5ef0055e05 rt(d3d9): fix vertex assignments accidentally searching fragment
1c6581d737 rt(d3d9): set colorwritemask to all
ac66b1b6f6 style: fix warnings
977975f4c7 doc: document naga reflect
3b9514ad38 doc: allow wgpu doc on apple
899fb50da6 chore: Release
162226ce44 ci: don't build locally
039fdfd41a ci: update OBS build platform
e13bb88df2 doc: update MSRV due to naga
7b375658c5 dep: update cargo.lock
3fb6e3843e dep: update to windows 0.58
3cda5b706d rt(d3d12): get rid of size in inputview
4d6793d305 rt(d3d11): get rid of input/output view wrappers
35f499f5e1 wgpu: enable pipeline caching
6ce711db26 ci: don't build Arch
d4b4366836 dep: update ash to 0.38
c646086df4 dep: update wgpu
f6cf642e50 chore: Release
98958dfb5e dep: update rustc_hash
b5d523e9f3 rt(mtl): move icrate definitions to objc2-metal
5e9ce1207c Revert "ci: temporarily remove deny-deprecated on ctypes to unblock ares"
1b0574c140 presets: show file name and details on io error
b84e104212 capi: fix malformed vulkan include

git-subtree-dir: thirdparty/librashader
git-subtree-split: 4abd48eb244e15ca40307f28fce0061627ff0143
2024-10-05 12:31:45 +01:00
Luke Usher 81d5cdba32 Merge commit '5151003fa4331d3a4473c32e6c7b4ebcd59e29ba' 2024-10-05 12:31:42 +01:00
Luke Usher 5151003fa4 Squashed 'thirdparty/libchdr/' changes from aa34b14191..aaca599e18
aaca599e18 Merge pull request #130 from notaz/release_lzma_init_buffers
2099836c2b release lzma init buffers
9b6ff6c3c2 Merge pull request #128 from scribam/zstd-legacy
85dd19217a Merge pull request #129 from scribam/arm-neon
71e57f533d lzma: extends neon support when hwcap is not available
a6c474ddee zstd: disable legacy support

git-subtree-dir: thirdparty/libchdr
git-subtree-split: aaca599e18e43933fc193bd1b715c368c306208b
2024-10-05 12:31:42 +01:00
Luke Usher 349f1d281c Squashed 'thirdparty/sljit/' changes from c2e49625e4..f6326087b3
f6326087b3 Improve op flags operation on x86
2a79c59737 Fix sign conversion warning on Windows arm64 (#270)
7a6ceb3e03 Fix examples (#269)
2c105e2461 Fixed a compare logical case on s390x
4c4802dd4c Emit brk #0xf000 for breakpoint opcode on arm64 (#267)
3b9c0c8925 Enable public usage of SLJIT_LOCALS_OFFSET (#264)
4dd388a736 loongarch: add memory fence & support tmp register for atomic (#263)
8c089bd584 Implement m,emory fence
d21a5448f6 Fix compiler warning
f9f512c080 Support tmp register for atomic
883118537c Add action (#259)
8099661b54 Add SLJIT_ATOMIC_USE_LS/CAS support to LoongArch (#261)
728db2007a riscv: only enable SIMD if supported by toolchain (#260)
8727735933 Bitmanipulation instructions on RISC-V (#258)
c85dd1dd97 Rework sljit_emit_enter argument passing
3e5568bfcc Add more tmp reg tests
bd056ab1df Add control flags to atomic operations
ee8861243f loongarch: Implement ll/sc support for atomic operations (#254)
d3a10d1986 x86: avoid SIGILL in CPUs with AVX but without AVX2 (#256)
460f02a1b8 x86: check for extended function availability before using (#255)
0a74f16bea x86: improve execute_cpuid() portability (#251)
7b0fd86bd5 test: avoid leaking compiler on early exit (#253)
31cfa2fef2 Add shuffle support for LoongArch (#252)
06a5bafd7c Initial implementation of riscv simd
5ad2541117 x86: improve execute_get_xcr0_low() portability (#250)
6128486813 Implement atomic store on ppc and mips
fcade55c27 Update atomic on s390x
8bcd711708 Rework atomic load/store
bd221f0e86 Support non-overlaping vector registers

git-subtree-dir: thirdparty/sljit
git-subtree-split: f6326087b3404efb07c6d3deed97b3c3b8098c0c
2024-10-05 12:31:38 +01:00
Luke Usher c6a838d6ee Merge commit '349f1d281c29a3af9f2814399028e0e7bc829c96' 2024-10-05 12:31:38 +01:00
Cheesemeister3k cac4aab301 #1485 [SNES] NTT Data Keypad (#1660)
Test equipment used: NTT Data Keypad, Raphnet ADAP-2XSNES-USB_V2 and
test32.sfc, Analogue Super Nt.
2024-10-05 12:25:28 +01:00
Factor 5911338cac Add support for 256KB of SRAM for SNES (#1616)
256KB of SRAM is possible on hardware and many hacks use it (Super
Metroid Practice ROM, Super Mario Bros. Maker, etc.). It could be
implemented in Ares in many ways, but I limited the ramSize to 1-8 with
a wrap-around as values higher than 8 wrap-around when used (9 is the
same as 1, 10 is the same as 2, etc. verified by
[kandowontu](https://github.com/kandowontu)).
2024-10-05 12:25:16 +01:00
png183 c0af33d4ce gba: improve SIO register handling (#1662)
Implements the following changes:

- Bits 8-11 of SIOCNT should be read/write
- Mode specified by SIOCNT uses 2 bits rather than 1
- Lower 3 bits of JOYCNT are cleared when 1's are written
2024-10-05 12:22:31 +01:00
hackgrid ea77623238 desktop-ui: enable loading rom folders from the cmd line (#1656)
Needs to merge #1654 first.

Enables loading folders instead files from cmd line.
Removes loading firmware files from rom folders in sfc mia (firmware
data would be loaded twice, db hashes would not match anymore).
2024-10-01 16:10:54 +01:00
png183 033752679f gba: add 2-cycle IRQ synchronizer and improve halted CPU timings (#1651)
Adds a 2-cycle synchronizer delay to IRQs. Unhalting the CPU also
appears to be delayed by 2 cycles.

The GBA CPU core currently steps in increments of 16 cycles when halted
or stopped to reduce emulation overhead. Since this optimization can
cause unhalt timings to be off by a few cycles, this PR reduces the step
size for halt mode and removes the optimization for stop mode.
Performance impact should be minimal in cases where performance is a
concern.
2024-09-26 14:23:54 +01:00
jcm 025fc6450a hiro/cocoa: Add bounds checking for table view context menus (#1650)
Right-clicking in a table view beyond the bounds of the defined rows in
the table would crash previously.
2024-09-25 09:57:13 +01:00
jcm d6858ad821 ruby/metal: Emit librashader shader creation errors (#1647)
Displaying errors from librashader shader loads in Metal will make
librashader debugging easier.
2024-09-18 18:34:10 +01:00
png183 0b46609e95 gba: add latches to DISPCNT background enable, object enable, and force blank bits (#1643)
Clearing the force blank bit or setting the background/object enable
bits in DISPCNT should only take effect after 3 scanlines.
2024-09-17 14:32:18 +01:00
jcm b5a8edc5d0 Address possible use of uninitialized variables (#1646)
Minor code cleanup. clang reports that it's possible under some
circumstances these variables are uninitialized when used.

Overall motivation is to utilize some stricter compiler settings in the
future and error on `-Wuninitialized`.
2024-09-17 14:32:07 +01:00
invertego 757a7dd670 Merge commit '950573df14f9307b7eaff4600370d76057aae466' into update_parallel_rdp 2024-09-15 05:27:45 -07:00
invertego 950573df14 Squashed 'ares/n64/vulkan/parallel-rdp/' changes from 7e5ad30b8..d1cc912c5
d1cc912c5 Update to 1f69c762be68feb9fcd5276d75acc6e5a6160a19
1a8cbce2f Update to fe5becd13638873db90d46e7ba7d48255971f82a
353ab9d38 Update to a2b0e8503ba525d70c61bccbe59c87d14daf89a6

git-subtree-dir: ares/n64/vulkan/parallel-rdp
git-subtree-split: d1cc912c5c47abaf9b6b155d3cd15255df65cf5b
2024-09-15 05:27:26 -07:00
Giovanni Bajo f43da416fd n64: refactor devirtualize and memory ops, force JIT only with instruction cache (#1635)
This change contains a large refactoring with no functional changes,
plus a small functional change that will help speeding up the JIT.

The refactoring allows CPU::devirtualize to return all the information
regarding the memory access. This in turn allows to simplify all memory
ops (which contained lots of duplicated code) to use devirtualize,
reducing code duplication.

The functional change is that we now use JIT only when running code from
icache (which is 99.9999% of the times). Running code without icache is
extremely slow on real hardware and only happens in specific situations
(eg: during boot when RDRAM is not initialized). By limiting the JIT to
run from icache, we open the door to implement proper icache support in
the JIT and finish remove the instruction epilogue with its slow
"instruction cache stepper" (which in addition to being slow, is also
inaccurate and make us fail cache test ROMs).
2024-09-08 13:45:09 +01:00
18f45ddc85 n64: add support for multi-byte writes to gdb (#1620)
Currently, gdb hooks in n64 doesn't allow for large sizes of writes
because it wouldn't be obvious which data size use on the bus. While
this is true, it doesn't really matter for RDRAM where all data sizes
work in the obvious, correct way. So relax the constraint to allow
writing large portions of RDRAM with a single gdb command.

Co-authored-by: Chase Meadors <[email protected]>
Co-authored-by: Luke Usher <[email protected]>
2024-09-03 09:49:40 +01:00
Giovanni Bajo 7135646c44 Update parallelRDP and MoltenVK (#1634) 2024-09-03 09:49:25 +01:00
invertegoandGiovanni Bajo 4ab8472a53 n64: fix instruction tracing with recompiler (#1629)
Co-authored-by: Giovanni Bajo <[email protected]>
2024-09-02 14:08:56 +01:00
Screwtapello a47e793b57 Stage resources into the output directory on Linux. (#1627)
Originally, to run ares on Linux after building it, you'd `make install`
which copied everything into the right places in your home directory.
Windows and macOS don't have the same traditions about installing apps,
so on those platforms the makefile staged a "portable" installation in
the output directory.

Since then, `make install` was modified to install ares system-wide.
It's possible to use it to install ares into your home directory, but a
bit overkill. For consistency, let's also stage a "portable"
installation in the output directory on Linux and the BSDs, so it's
easier to test on those platforms.
2024-09-02 11:36:41 +01:00
invertego 1ffb4f6d5a n64: use devirtualize for code block lookup (#1630)
Essentially a revert of fbaf7d8118

This optimization was found to compromise correctness due to the lack of
alignment checks. If something like this proves truly beneficial for
performance, we can bring it back.
2024-09-02 11:35:45 +01:00
remutro aa350116d4 Add option to enable TMSS boot rom for Mega Drive (#1632)
If you like to slow down booting into your game and want to read the
same old text each time on the Mega Drive, the option is yours now! This
is available as a choice in Settings > Options now. By default, this
will not be enabled (same behavior as existed prior to this PR). You
don't need to specify anything in the firmware section, ares had the
plumbing in place all along, it was just hardcoded to not load the tmss
boot rom.
2024-09-02 11:35:07 +01:00
png183 e8a5579cb7 gba: latch IE and IF values for 1 cycle, and improve stop mode emulation (#1631)
Improved interrupt timings, and made sure stop mode exits only once the
requested keypad input is registered.
2024-09-01 09:00:28 +01:00
Screwtapello f091fcfacd Fix detection of the Sufami Turbo base cartridge. (#1628)
The Sufami Turbo base cartridge is listed in the Super Famicom verified
dump database, so it did not use the heuristics. It turns out the
heuristic detection wouldn't have worked anyway - although the game's
header does contain the serial A9PJ, the heuristic revision() method
does not report that serial at all.

Meanwhile, the serial A9PJ is *also* used by the game Bishoujo Senshi
Sailor Moon SuperS - Fuwafuwa Panic, so loading this game would prompt
for Sufami Turbo mini-cartridges even though the game could not make use
of them.

I have used mia to generated heuristic manifests for every SNES/SFC game
in the No-Intro set, and the only difference introduced by this change
is that the Sufami Turbo base cartridge is now detected as having Sufami
Turbo slots, and Fuwafuwa Panic is not.

It took me a little messing around to find a syntax for comparing an
`array_view<u8>` that the compiler would accept; if there's some more
concise or idiomatic way to do it, please let me know.

Of the other emulators I surveyed, bsnes works just like ares did,
MesenS doesn't seem to support the Sufami Turbo, and snes9x uses a
slightly stricter check than I implemented:


https://github.com/snes9xgit/snes9x/blob/85591435763dede7ef111aab8070cdf2d5a7da49/memmap.cpp#L1016-L1023
2024-08-29 12:22:43 +01:00
Luke Usher fa9d350a66 md: sync more regularly when emulating 32X
Fixes a hang in Knuckles Chaotix at the cost of performance.

Needs further investigation.
2024-08-28 16:16:41 +01:00
1207 changed files with 98409 additions and 53383 deletions

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/BlankSpruce/gersemi/master/gersemi/configuration.schema.json
color: false
definitions: [ares/CMakeLists.txt]
line_length: 120
indent: 2
list_expansion: favour-inlining
quiet: false
unsafe: false
warn_about_unknown_commands: false
workers: 10
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env sh
set -euo pipefail
# configure
cmake --preset $TARGET_PRESET
# change into the build directory
pushd build
# build; pipe output to render warnings neatly
xcodebuild -configuration RelWithDebInfo \
DEBUG_INFORMATION_FORMAT="dwarf-with-dsym" \
2>&1 | xcbeautify --renderer github-actions
popd
# package debug symbols
# move dependency dSYMs to build output directory
ditto .deps/ares-deps-macos-universal/lib/*.dSYM build/desktop-ui/RelWithDebInfo
mkdir build/dsyms
# ares.app.dSYM already exists alongside ares.app; package it with the rest
mv build/desktop-ui/RelWithDebInfo/*.dSYM build/dSYMs/
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail
# configure
cmake --preset $TARGET_PRESET
# change into the build directory
pushd build
ninja
popd
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env sh
set -euo pipefail
if [ "$CROSS_COMPILE" = true ]; then
cmake --preset $NATIVE_PRESET -B build_native
pushd build_native
# build sourcery natively so it may be invoked during cross-compilation
cmake --build . --target sourcery --config RelWithDebInfo
popd
fi
cmake --preset $TARGET_PRESET
pushd build
cmake --build . --config RelWithDebInfo
if [ "$CROSS_COMPILE" = true ]; then
cp ../.deps/ares-deps-windows-arm64/lib/*.pdb desktop-ui/rundir/
else
cp ../.deps/ares-deps-windows-x64/lib/*.pdb desktop-ui/rundir/
fi
mkdir PDBs
mv desktop-ui/rundir/*.pdb PDBs/
popd
+45
View File
@@ -0,0 +1,45 @@
set -eu
case ${GITHUB_REF} in
refs/tags/*) suffix="-${GITHUB_REF#refs/tags/}" ;;
refs/heads/master) suffix="-nightly" ;;
*) suffix="" ;;
esac
bindir="${GITHUB_WORKSPACE}/bin"
# Hack: Workaround for GitHub artifacts losing attributes.
chmod +x ${bindir}/ares-macos-universal/ares.app/Contents/MacOS/ares
for package in macos-universal
do
mkdir "${package}"
cd "${package}"
# Package ares.
outdir=ares${suffix}
mkdir ${outdir}
mkdir ${outdir}-dSYMs
cp -a ${bindir}/ares-${package}-dSYMs/*.dSYM ${outdir}-dSYMs
cp -a ${bindir}/ares-${package}/*.app ${outdir}
zip -r ../ares-${package}.zip ${outdir}
zip -r ../ares-${package}-dSYMs.zip ${outdir}-dSYMs
cd -
done
for package in windows-x64 windows-clang-cl-x64 windows-clang-cl-arm64
do
mkdir "${package}"
cd "${package}"
# Package ares.
outdir=ares${suffix}
mkdir ${outdir}
mkdir ${outdir}-PDBs
cp -a ${bindir}/ares-${package}-PDBs/*.pdb ${outdir}-PDBs
zip -r ../ares-${package}-PDBs.zip ${outdir}-PDBs
rm -rf ${bindir}/ares-${package}/PDBs
cp -a ${bindir}/ares-${package}/* ${outdir}
zip -r ../ares-${package}.zip ${outdir}
cd -
done
+14 -29
View File
@@ -51,12 +51,8 @@ jobs:
windres: rc
shell: bash
msvc-arch: x64_arm64
- name: macos-compat
os: macos-12
compiler: clang++
shell: sh
- name: macos-latest
os: macos-latest
- name: macos-universal
os: macos-15
compiler: clang++
shell: sh
- name: ubuntu
@@ -120,26 +116,21 @@ jobs:
- name: Install macOS Dependencies
if: runner.os == 'macOS'
run: |
if [ $ImageOS == "macos14" ]; then
sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
echo "Set Xcode version to 15.2 for macos-latest build."
elif [ $ImageOS == "macos12" ]; then
sudo xcode-select -s /Applications/Xcode_13.4.app/Contents/Developer
echo "Set Xcode version to 13.4 for macos-compat build."
fi
brew install make ninja cmake
sudo xcode-select -s /Applications/Xcode_16.1.0.app/Contents/Developer
export MACOSX_DEPLOYMENT_TARGET=10.13
brew install ninja cmake
pip install --no-input setuptools
rustup toolchain install nightly
rustup default nightly
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
echo "MAKE=gmake" >> $GITHUB_ENV
pushd thirdparty/SDL
./build-SDL.sh
popd
pushd thirdparty/MoltenVK
./build-moltenvk.sh
popd
export MACOSX_DEPLOYMENT_TARGET=10.15
pushd thirdparty/librashader
./build-librashader.sh
popd
@@ -168,9 +159,9 @@ jobs:
certificatesha1: '${{ secrets.WIN_CERTHASH }}'
certificatename: '${{ secrets.WIN_CERTNAME }}'
folder: 'desktop-ui/out'
timestampUrl: 'http://timestamp.digicert.com'
timestampUrl: 'http://timestamp.digicert.com'
- name: "macOS: notarize"
if: runner.os == 'macOS' && github.event_name != 'pull_request'
if: false
continue-on-error: ${{ github.repository != 'ares-emulator/ares' }}
run: |
ditto -c -k --keepParent desktop-ui/out/ares.app /tmp/ares.zip
@@ -188,7 +179,7 @@ jobs:
release:
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
if: false
runs-on: ubuntu-latest
needs:
- build
@@ -213,10 +204,9 @@ jobs:
bindir="${GITHUB_WORKSPACE}/bin"
# Hack: Workaround for GitHub artifacts losing attributes.
chmod +x ${bindir}/ares-macos-latest/ares.app/Contents/MacOS/ares
chmod +x ${bindir}/ares-macos-compat/ares.app/Contents/MacOS/ares
chmod +x ${bindir}/ares-macos-universal/ares.app/Contents/MacOS/ares
for package in windows windows-msvc-arm64 macos-latest macos-compat
for package in windows windows-msvc-arm64 macos-universal
do
mkdir "${package}"
cd "${package}"
@@ -315,17 +305,12 @@ jobs:
- name: Upload ares-windows-msvc-arm64
uses: actions/upload-release-asset@v1
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows-msvc-arm64.zip', asset_name: 'ares-windows-msvc-arm64.zip', asset_content_type: 'application/zip' }
- name: Upload ares-macos-latest
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows-msvc-arm64.zip', asset_name: 'ares-windows-msvc-arm64.zip', asset_content_type: 'application/zip' }
- name: Upload ares-macos-universal
uses: actions/upload-release-asset@v1
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-macos-latest.zip', asset_name: 'ares-macos-latest.zip', asset_content_type: 'application/zip' }
- name: Upload ares-macos-compat
uses: actions/upload-release-asset@v1
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-macos-compat.zip', asset_name: 'ares-macos-compat.zip', asset_content_type: 'application/zip' }
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-macos-universal.zip', asset_name: 'ares-macos-universal.zip', asset_content_type: 'application/zip' }
# - name: Upload ares-ubuntu
# uses: actions/upload-release-asset@v1
# env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
# with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-ubuntu.zip', asset_name: 'ares-ubuntu.zip', asset_content_type: 'application/zip' }
+153
View File
@@ -0,0 +1,153 @@
name: Build (New)
on:
workflow_call:
inputs:
codesign:
description: Enable codesigning
required: false
default: false
type: boolean
jobs:
build:
strategy:
fail-fast: false
matrix:
program:
- ares
config:
- RelWithDebInfo
platform:
- name: windows-x64
os: windows-latest
compiler: clang++
shell: 'msys2 {0}'
msystem: clang64
install: mingw-w64-clang-x86_64-clang
target-cmake-preset: windows-ci-mingw-native
- name: windows-x64-gcc
os: windows-latest
compiler: g++
shell: 'msys2 {0}'
msystem: mingw64
install: mingw-w64-x86_64-toolchain
target-cmake-preset: windows-ci-mingw-native
- name: windows-clang-cl-x64
os: windows-latest
windres: rc
shell: bash
target-cmake-preset: windows-ci-cl-native
- name: windows-clang-cl-arm64
os: windows-latest
windres: rc
shell: bash
target-cmake-preset: windows-ci-cl-cross
native-cmake-preset: windows-ci-cl-native
- name: windows-msvc-x64
os: windows-latest
windres: rc
shell: bash
target-cmake-preset: windows-ci-msvc-native
- name: windows-msvc-arm64
os: windows-latest
windres: rc
shell: bash
target-cmake-preset: windows-ci-msvc-cross
native-cmake-preset: windows-ci-msvc-native
- name: macos-universal
os: macos-15
compiler: clang++
shell: sh
install: cmake ccache xcbeautify
target-cmake-preset: macos-ci-universal
- name: ubuntu
os: ubuntu-latest
compiler: g++
shell: bash
install: cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
target-cmake-preset: ubuntu-ci
name: ${{ matrix.program }}-${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
defaults:
run:
shell: ${{ matrix.platform.shell }}
steps:
- name: Install MSYS2 Dependencies
if: matrix.platform.shell == 'msys2 {0}'
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.platform.msystem }}
install: make git cmake ccache ninja ${{ matrix.platform.install }}
- name: "macOS: Import Certificate"
if: runner.os == 'macOS' && inputs.codesign
uses: apple-actions/import-codesign-certs@v3
continue-on-error: ${{ !inputs.codesign }}
with:
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_DATA }}
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
- name: Checkout source code
uses: actions/checkout@v4
with:
fetch-tags: true
fetch-depth: 0
- name: Install Linux Dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update -y -qq
sudo apt-get install ${{ matrix.platform.install }}
- name: Install macOS Dependencies
if: runner.os == 'macOS'
run: |
brew install ${{ matrix.platform.install }}
- name: "Build: Linux"
if: runner.os == 'Linux'
run: .github/scripts/build_ubuntu.sh
env:
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
- name: "Build: Windows"
if: runner.os != 'macOS' && runner.os != 'Linux'
run: .github/scripts/build_windows.sh
env:
CROSS_COMPILE: ${{ matrix.platform.native-cmake-preset != '' }}
NATIVE_PRESET: ${{ matrix.platform.native-cmake-preset }}
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
- name: "Windows: sign"
if: runner.os == 'Windows' && inputs.codesign
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
with:
certificate: '${{ secrets.WIN_CERTIFICATE }}'
password: '${{ secrets.WIN_PASSWORD }}'
certificatesha1: '${{ secrets.WIN_CERTHASH }}'
certificatename: '${{ secrets.WIN_CERTNAME }}'
folder: 'build/desktop-ui/rundir/'
timestampUrl: 'http://timestamp.digicert.com'
- name: "Build: macOS"
if: runner.os == 'macOS'
run: .github/scripts/build_macos.sh
env:
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
- name: Upload Build (Windows)
if: runner.os != 'macOS' && runner.os != 'Linux'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}
path: build/desktop-ui/rundir/*
- name: Upload Build (macOS)
if: runner.os == 'macOS'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}
path: build/desktop-ui/RelWithDebInfo/
- name: Upload Debug Symbols (Windows)
if: runner.os != 'macOS' && runner.os != 'Linux'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
path: build/PDBs/*
- name: Upload Debug Symbols (macOS)
if: runner.os == 'macOS'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}-dSYMs
path: build/dSYMs/*
+17
View File
@@ -0,0 +1,17 @@
name: Pull Request
run-name: ${{ github.event.pull_request.title }} PR run
on:
pull_request:
branches: [ '*' ]
types: [ opened, synchronize, reopened ]
permissions:
contents: read
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
jobs:
build-project:
name: Build
uses: ./.github/workflows/build_new.yml
permissions:
contents: read
+24
View File
@@ -0,0 +1,24 @@
name: Push
on:
push:
branches: [ '*' ]
tags: [ 'v*' ]
concurrency:
group: '${{ github.workflow }} @ ${{ github.head_ref || github.ref }}'
cancel-in-progress: true
permissions:
contents: write
jobs:
build:
name: Build ares
uses: ./.github/workflows/build_new.yml
secrets: inherit
with:
codesign: true
release:
name: Release
needs: build
secrets: inherit
uses: ./.github/workflows/release.yml
with:
notarize: true
+68
View File
@@ -0,0 +1,68 @@
name: Release
on:
workflow_call:
inputs:
notarize:
description: Notarize build (macOS only)
required: false
default: true
type: boolean
jobs:
release:
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
path: 'src'
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: 'bin'
- name: "macOS: notarize"
if: inputs.notarize
run: |
ditto -c -k --keepParent ${{ github.workspace }}/bin/ares-macos-universal/ares.app /tmp/ares.zip
xcrun notarytool submit /tmp/ares.zip --apple-id "$MACOS_NOTARIZATION_USERNAME" --password "$MACOS_NOTARIZATION_PASSWORD" --team-id "$MACOS_NOTARIZATION_TEAMID" --wait
xcrun stapler staple ${{ github.workspace }}/bin/ares-macos-universal/ares.app
env:
MACOS_NOTARIZATION_USERNAME: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
MACOS_NOTARIZATION_PASSWORD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
- name: Package Artifacts
run: src/.github/scripts/package_artifacts.sh
- name: Check Release Tag ☑️
id: check
run: |
now=$(date +'%Y-%m-%d')
subject=$(git -C src log -1 --pretty=%s)
if [[ ${GITHUB_REF_NAME} == master ]];
then
echo "tag=nightly" >> $GITHUB_OUTPUT
versionName="nightly ${now}"
echo "versionName=${versionName}" >> $GITHUB_OUTPUT
echo "description=${subject}" >> $GITHUB_OUTPUT
else
echo "tag=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
echo "versionName=${GITHUB_REF_NAME}" >> $GITHUB_OUTPUT
description="This is ares ${GITHUB_REF_NAME}, released on ${now}."
echo "description=${description}" >> $GITHUB_OUTPUT
fi
- name: Create Release 🛫
id: create_release
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
with:
draft: ${{ github.ref != 'refs/heads/master' }}
tag_name: ${{ steps.check.outputs.tag }}
name: ares ${{ steps.check.outputs.versionName }}
body: ${{ steps.check.outputs.description }}
files: |
${{ github.workspace }}/ares-macos-universal.zip
${{ github.workspace }}/ares-macos-universal-dSYMs.zip
${{ github.workspace }}/ares-windows-x64.zip
${{ github.workspace }}/ares-windows-x64-PDBs.zip
${{ github.workspace }}/ares-windows-clang-cl-x64.zip
${{ github.workspace }}/ares-windows-clang-cl-x64-PDBs.zip
${{ github.workspace }}/ares-windows-clang-cl-arm64.zip
${{ github.workspace }}/ares-windows-clang-cl-arm64-PDBs.zip
+40 -16
View File
@@ -1,18 +1,42 @@
*.moc
*.user
*.xcuserdata
.vs/
.vscode/
.idea/
cmake-*/
obj/
out/
obj-amd64/
obj-arm64/
out-amd64/
out-arm64/
# Exclude everything
/*
# Except for default project files
!/.github
!/ares
!/desktop-ui
!/hiro
!/cmake
!/libco
!/mia
!/nall
!/ruby
!/scripts
!/tests
!/thirdparty
!/tools
!/GNUMakefile
!/LICENSE
!/README.md
!.editorconfig
!.gitignore
!.gitattributes
!.gersemirc
!deps.json
!CMakeLists.txt
!CMakePresets.json
thirdparty/SDL/SDL
thirdparty/SDL/libSDL2-2.0.0.dylib
macos-xcode/
.swiftpm
*.xcodeproj
desktop-ui/out
desktop-ui/obj
ruby/video/metal/shaders.metallib
ruby/video/metal/shaders.ir
ares/ares/resource/resource.cpp
ares/ares/resource/resource.hpp
hiro/resource/resource.cpp
hiro/resource/resource.hpp
desktop-ui/resource/resource.cpp
desktop-ui/resource/resource.hpp
tests/arm7tdmi/tests
tests/m68000/tests
+55
View File
@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.28...3.30)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE)
project(ares VERSION ${ARES_VERSION_CANONICAL})
include(compilerconfig)
include(defaults)
include(helpers)
add_subdirectory(cmake)
add_subdirectory(thirdparty)
add_subdirectory(nall)
add_subdirectory(libco)
add_subdirectory(ruby)
add_subdirectory(hiro)
# gersemi: off
set(
ARES_CORES
a26 fc sfc sg ms md ps1 pce ng msx cv myvision gb gba ws ngp spec n64
CACHE STRING LIST
)
# gersemi: on
add_subdirectory(ares)
add_subdirectory(mia)
add_subdirectory(desktop-ui)
option(ARES_BUILD_OPTIONAL_TARGETS "Include supplemental tools and tests" OFF)
if(ARES_BUILD_OPTIONAL_TARGETS)
add_subdirectory(tests/arm7tdmi)
add_subdirectory(tests/i8080)
add_subdirectory(tests/m68000)
if(NOT OS_WINDOWS AND NOT OS_MACOS)
add_subdirectory(tools/genius)
else()
target_disable_subproject(genius "genius (database editor)")
endif()
add_subdirectory(tools/mame2bml)
else()
target_disable_subproject(arm7tdmi "arm7tdmi processor test harness")
target_disable_subproject(i8080 "i8080 processor test harness")
target_disable_subproject(m68000 "m68000 processor test harness")
target_disable_subproject(mame2bml "mame2bml (MAME manifest converter)")
target_disable_subproject(genius "genius (database editor)")
endif()
add_subdirectory(tools/sourcery)
message_configuration()
return()
+176
View File
@@ -0,0 +1,176 @@
{
"version": 3,
"cmakeMinimumRequired": {
"major": 3,
"minor": 28,
"patch": 0
},
"configurePresets": [
{
"name": "baseCacheVars",
"hidden": true,
"cacheVariables": {
"ARES_PROFILE_ACCURACY": false,
"ARES_BUILD_LOCAL": true,
"ENABLE_CCACHE": true
}
},
{
"name": "macos",
"displayName": "macOS",
"description": "Xcode project (host architecture by default)",
"inherits": ["baseCacheVars"],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"generator": "Xcode",
"binaryDir": "${sourceDir}/build_macos",
"cacheVariables": {
"ARES_CODESIGN_IDENTITY": {"type": "STRING", "value": "$penv{CODESIGN_IDENT}"},
"ARES_CODESIGN_TEAM": {"type": "STRING", "value": "$penv{CODESIGN_TEAM}"},
"ARES_BUILD_OPTIONAL_TARGETS": true,
"ENABLE_CCACHE": true
}
},
{
"name": "windows",
"displayName": "Windows (Visual Studio, ClangCL)",
"description": "Visual Studio project using ClangCL (host architecture)",
"inherits": ["baseCacheVars"],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"binaryDir": "${sourceDir}/build_vsclang",
"generator": "Visual Studio 17 2022",
"toolset": "ClangCL",
"cacheVariables": {
"ENABLE_CCACHE": true
}
},
{
"name": "windows-msvc",
"displayName": "Windows (Visual Studio, MSVC)",
"description": "Visual Studio project using MSVC (host architecture)",
"inherits": ["baseCacheVars"],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"binaryDir": "${sourceDir}/build_msvc",
"generator": "Visual Studio 17 2022",
"cacheVariables": {
"ENABLE_CCACHE": true
}
},
{
"name": "macos-ci-universal",
"displayName": "macOS for CI",
"description": "Universal binary for building on Github Actions",
"inherits": ["baseCacheVars"],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"generator": "Xcode",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_OSX_ARCHITECTURES": {"type": "STRING", "value": "x86_64;arm64"},
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "10.13"},
"ARES_CODESIGN_IDENTITY": {"type": "STRING", "value": "$penv{MACOS_CERTIFICATE_NAME}"},
"ARES_CODESIGN_TEAM": {"type": "STRING", "value": "$penv{MACOS_NOTARIZATION_TEAMID}"},
"ENABLE_CCACHE": true,
"ARES_BUILD_LOCAL": false,
"ARES_UNITY_CORES": true,
"ARES_BUILD_OPTIONAL_TARGETS": true
}
},
{
"name": "windows-ci-base",
"hidden": true,
"inherits": ["baseCacheVars"],
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": {"type": "STRING", "value": "RelWithDebInfo"},
"ENABLE_CCACHE": true,
"ARES_BUILD_LOCAL": false,
"ARES_BUILD_OPTIONAL_TARGETS": true,
"ARES_UNITY_CORES": true,
"ARES_PRECOMPILE_HEADERS": true
}
},
{
"name": "windows-ci-mingw-native",
"displayName": "Windows for CI (x64 MSYS2/MinGW Clang)",
"description": "Single-arch binary for building on Github Actions",
"inherits": ["windows-ci-base"],
"generator": "Ninja"
},
{
"name": "windows-ci-cl-native",
"displayName": "Windows for CI (x64 ClangCL)",
"description": "Single-arch binary for building on Github Actions",
"generator": "Visual Studio 17 2022",
"inherits": ["windows-ci-base"],
"toolset": "ClangCL"
},
{
"name": "windows-ci-cl-cross",
"displayName": "Windows for CI (arm64 ClangCL)",
"description": "Single-arch binary for building on Github Actions",
"inherits": ["windows-ci-base"],
"generator": "Visual Studio 17 2022",
"architecture": "arm64",
"toolset": "ClangCL",
"cacheVariables": {
"ARES_CROSSCOMPILING": true
}
},
{
"name": "windows-ci-msvc-native",
"displayName": "Windows for CI (x64 MSVC)",
"description": "Single-arch binary for building on Github Actions",
"generator": "Visual Studio 17 2022",
"inherits": ["windows-ci-base"]
},
{
"name": "windows-ci-msvc-cross",
"displayName": "Windows for CI (arm64 MSVC)",
"description": "Single-arch binary for building on Github Actions",
"generator": "Visual Studio 17 2022",
"architecture": "arm64",
"inherits": ["windows-ci-base"],
"cacheVariables": {
"ARES_CROSSCOMPILING": true
}
},
{
"name": "ubuntu-ci",
"displayName": "Ubuntu CI (x64 gcc)",
"description": "Single-arch binary for building on Github Actions",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": {"type": "STRING", "value": "RelWithDebInfo"},
"ENABLE_CCACHE": true,
"ARES_BUILD_LOCAL": false,
"ARES_BUILD_OPTIONAL_TARGETS": true,
"ARES_PRECOMPILE_HEADERS": false
}
}
],
"buildPresets": [
{
"name": "windows",
"configurePreset": "windows",
"displayName": "Windows build (host architecture)",
"description": "Windows build (host architecture)",
"configuration": "RelWithDebInfo"
}
]
}
+1 -1
View File
@@ -1,7 +1,7 @@
----------------------------------------------------------------------
ares
Copyright (c) 2004-2021 ares team, Near et al
Copyright (c) 2004-2024 ares team, Near et al
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
+8 -118
View File
@@ -1,4 +1,4 @@
![ares logo](https://github.com/ares-emulator/ares/blob/master/ares/ares/resource/logo.png)
<img src="https://github.com/ares-emulator/ares/blob/master/ares/ares/resource/logo@2x.png" width="350"/>
[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://github.com/higan-emu/ares/blob/master/LICENSE)
@@ -17,127 +17,17 @@ Nightly Builds
Automated, untested builds of ares are available for Windows and macOS as a [pre-release](https://github.com/higan-emu/ares/releases/tag/nightly).
Only the latest nightly build is kept.
Prerequisites
Building ares
-------------
### *nix building
Build instructions are available on the ares wiki. See build instructions for:
###### Minimum required packages:
```
g++ make pkg-config libgtk-3-dev libcanberra-gtk-module libgl-dev libasound2-dev
```
###### Additional Audio Drivers
ares supports additional audio drivers besides the ALSA drivers included above. Installing these additional packages will allow them to be selected in Settings > Drivers:
`libao-dev libopenal-dev`
###### GTK2 & GTK3
By default, GTK3 is used, but support for GTK2 is available. You will need to install the additional package `libgtk2.0-dev` as well as specifying the command line option `hiro=gtk2` at compile time.
###### SDL2 for input
If you would like to use SDL for input (e.g. for using a controller), you will need to install the `libsdl2-dev` and `libsdl2-2.0-0` packages and perform a clean build of ares.
You should then be able to select SDL for input in the Settings > Drivers menu.
##### Building with clang
clang++ is now the preferred compiler for ares. If clang is detected on Windows/macOS/BSD, it will be selected by default. On Linux and other platforms, g++ remains the default if present. To build with clang, it is necessary to install both the `clang` and `lld` packages. If you would like to manually specify a compiler, you can use the following option: `compiler=[g++|clang++]`
##### Librashader Support
If you do not want to include librashader support, you can pass the following option to the `make` command to skip these requirements using: `librashader=false`
Librashader requires rust in order to build. You can install it with the following command:
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
rustup toolchain install nightly
```
In order to build librashader, change into the `ares/thirdparty/librashader` directory and run the script `build-librashader.sh`
Note that once the build completes, it will instruct you to run three copy commands to install the library on your system. These paths may be different depending on Linux distribution.
--------------
### Windows building
To build on Windows, using MSYS2 is recommended which can be download [here](https://www.msys2.org/). Follow the instructions
on this page to install and setup an appropriate MINGW64 environment. Running the command:
```
pacman -S --needed base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-SDL2
```
from the MSYS2 MSYS terminal should setup everything you need to compile ares. Note that in order to compile, you will want to be in a MINGW64 terminal window after install and setup is complete.
##### Building with clang
clang is available through Visual Studio (or Build Tools for Visual Studio) through its installer and can be used to build ares. You will still need to supply GNU make in this instance. MSYS2 also offers a clang environment. You will want to make sure you select the clangw64 option during installation of MSYS2 which should provide and additional CLANG64 pre-configured environment. Install the clang toolchain package from the MSYS2 terminal:
```
pacman -S mingw-w64-clang-x86_64-toolchain mingw-w64-clang-x86_64-SDL2
```
Once complete, open a CLANG64 terminal window and proceed with building ares.
###### Debug Symbols
When building with clang, by default symbols will be generated for debug builds using an MSVC compatible format (CodeView) for use with Windows debugging tools. In order to generate GDB compatible symbols, specify the following option: `symformat=gdb`
###### Librashader Support
ares has introduced support for the [librashader](https://github.com/SnowflakePowered/librashader) library, which is a preprocessor, compiler, and runtime for RetroArch 'slang' shaders. If you are not interested in working with librashaders, you can pass the following option to the `make` command to skip these requirements using: `librashader=false`
Building the librashader library on Windows requires Rust. Follow these steps to prepare your system and build the librashader library:
1. Download and execute the rustup-init.exe installer from: https://rustup.rs/
2. Open a new Windows terminal and run the following commands:
```
rustup toolchain install nightly
rustup default nightly
```
3. With Rust successfully installed, you will need to update your PATH environment variable within your MSYS2 environment. In an MSYS2 shell, open $HOME/.bash_profile and append something like the following (note you will need to replace both instances of %USER_NAME% with the real user name you used to install Rust):
```
if [ -d "/C/Users/%USER_NAME%/.cargo/bin" ] ; then
PATH="/C/Users/%USER_NAME%/.cargo/bin:${PATH}"
fi
```
4. Open a new MSYS2 based shell for the compiler you are using (MinGW64|CLANG64|UCRT64), execute `rustup` to validate the path is set properly within your MSYS2 environment.
5. In your MSYS2 compiler shell, `cd` into the `ares/thirdparty/librashader` directory
6. Execute the build script, build should complete successfully:
```
./build-librashader.sh
```
This only needs to be done once, or anytime the librashader library is updated. Once built, ares will build with librashader support by default requiring no additional flags.
Compilation
-----------
Check out the source code by running this command:
```
git clone https://github.com/ares-emulator/ares.git
```
From the root of the project directory run:
```
make -j4
```
`-j#` indicates number of parallel build processes, and shouldn't be set higher than N-1 cores on your processor. Specifying this option can significantly decrease the time to build this project. There are multiple build types available and it defaults to an 'optimized' build. Build types can be specified using: `build=[debug|stable|release|minified|optimized]`
Build options can be found in the following two make files: nall/GNUmakefile desktop-ui/GNUmakefile
To start compilation from the beginning, run the following prior to compiling:
```
make clean
```
#### Building specific cores
If you would like to build a subset of cores, you can specify the `cores="core1 core2"` option. Currently available cores:
```
a26 fc sfc n64 sg ms md ps1 pce ng msx cv myvision gb gba ws ngp spec
```
Build Output
------------
There is a single binary produced at the end of compilation which can be found in `desktop-ui/out`. On OS's besides Linux, the `Database` & `Shader` directories are copied over here as well. On Linux, running `make install` after compilation will copy these directories and binary into suitable locations (see desktop-ui/GNUmakefile for details). Alternatively, these directories can be copied from `thirdparty/slang-shaders/*` into a `Shader` directory, and by copying `mia/Database/*`
* [Windows](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-Windows)
* [macOS](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-macOS)
* [Linux](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-Linux)
* [BSD](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-BSD)
For legacy Makefile build instructions, see [here](https://github.com/ares-emulator/ares/wiki/Legacy-Build-Instructions).
Command-line options
--------------------
+305
View File
@@ -0,0 +1,305 @@
add_library(ares STATIC ares/ares.cpp ares/memory/fixed-allocator.cpp)
add_library(ares::ares ALIAS ares)
option(ARES_PROFILE_ACCURACY "Build to prefer emulation accuracy over performance in certain specific areas" OFF)
option(ARES_PRECOMPILE_HEADERS "Precompile ares/ares.hpp header for performance" OFF)
option(
ARES_UNITY_CORES
"\
Build each core as one translation unit. Decreases cold build times but increases incremental build times. Slightly \
increases performance.
"
OFF
)
add_sourcery_command(ares ares/resource)
if(ARES_PRECOMPILE_HEADERS)
target_precompile_headers(ares PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:ares/ares.hpp>")
endif()
target_link_libraries(ares PUBLIC libco sljit nall)
if(ARES_PROFILE_ACCURACY)
target_compile_definitions(ares PUBLIC PROFILE_ACCURACY)
else()
target_compile_definitions(ares PUBLIC PROFILE_PERFORMANCE)
endif()
target_sources(
ares
PRIVATE ares/ares.cpp ares/ares.hpp ares/inline.hpp ares/platform.hpp ares/random.hpp ares/types.hpp
)
target_sources(
ares
PRIVATE
ares/debug/debug.cpp
ares/debug/debug.hpp
ares/memory/fixed-allocator.cpp
ares/memory/fixed-allocator.hpp
ares/memory/memory.hpp
ares/memory/readable.hpp
ares/memory/writable.hpp
)
target_sources(
ares
PRIVATE ares/scheduler/scheduler.cpp ares/scheduler/scheduler.hpp ares/scheduler/thread.cpp ares/scheduler/thread.hpp
)
target_sources(
ares
PRIVATE
ares/node/attribute.hpp
ares/node/class.hpp
ares/node/node.cpp
ares/node/node.hpp
ares/node/object.hpp
ares/node/peripheral.hpp
ares/node/port.hpp
ares/node/system.hpp
)
target_sources(ares PRIVATE ares/node/audio/audio.hpp ares/node/audio/stream.cpp ares/node/audio/stream.hpp)
target_sources(ares PRIVATE ares/node/component/component.hpp ares/node/component/real-time-clock.hpp)
target_sources(
ares
PRIVATE
ares/node/input/axis.hpp
ares/node/input/button.hpp
ares/node/input/input.hpp
ares/node/input/rumble.hpp
ares/node/input/trigger.hpp
)
target_sources(
ares
PRIVATE
ares/node/setting/boolean.hpp
ares/node/setting/integer.hpp
ares/node/setting/natural.hpp
ares/node/setting/real.hpp
ares/node/setting/setting.hpp
ares/node/setting/string.hpp
)
target_sources(
ares
PRIVATE
ares/node/video/screen.cpp
ares/node/video/screen.hpp
ares/node/video/sprite.cpp
ares/node/video/sprite.hpp
ares/node/video/video.hpp
)
if(OS_WINDOWS)
include(cmake/os-windows.cmake)
elseif(OS_MACOS)
include(cmake/os-macos.cmake)
elseif(OS_LINUX OR OS_FREEBSD OR OS_OPENBSD)
include(cmake/os-linux.cmake)
endif()
macro(ares_components)
list(APPEND ares.components ${ARGV})
set(ares.components ${ares.components} PARENT_SCOPE)
endmacro()
macro(ares_add_sources)
set(options "")
set(oneValueArgs CORE)
set(multiValueArgs PRIMARY INCLUDED UNITY)
cmake_parse_arguments(AAS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
target_sources(ares PRIVATE ${AAS_INCLUDED} ${AAS_PRIMARY})
if(ARES_UNITY_CORES)
list(APPEND AAS_INCLUDED ${AAS_PRIMARY})
target_sources(ares PRIVATE ${AAS_UNITY})
endif()
foreach(arg IN ITEMS ${AAS_INCLUDED})
list(APPEND ARES_HEADER_SOURCES "${AAS_CORE}/${arg}")
endforeach()
set(ARES_HEADER_SOURCES ${ARES_HEADER_SOURCES} PARENT_SCOPE)
endmacro()
list(TRANSFORM ARES_CORES STRIP)
if(a26 IN_LIST ARES_CORES)
enable_core("Atari 2600")
add_subdirectory(a26)
else()
disable_core("Atari 2600")
endif()
if(fc IN_LIST ARES_CORES)
enable_core("NES / Famicom")
add_subdirectory(fc)
else()
disable_core("NES / Famicom")
endif()
if(sfc IN_LIST ARES_CORES)
enable_core("SNES / Super Famicom")
add_subdirectory(sfc)
else()
disable_core("SNES / Super Famicom")
endif()
if(n64 IN_LIST ARES_CORES)
enable_core("Nintendo 64")
add_subdirectory(n64)
else()
disable_core("Nintendo 64")
endif()
if(sg IN_LIST ARES_CORES)
enable_core("Sega SG-1000")
add_subdirectory(sg)
else()
disable_core("Sega SG-1000")
endif()
if(ms IN_LIST ARES_CORES)
enable_core("Sega Master System / Mark III")
add_subdirectory(ms)
else()
disable_core("Sega Master System / Mark III")
endif()
if(md IN_LIST ARES_CORES)
enable_core("Sega Mega Drive / Genesis")
add_subdirectory(md)
else()
disable_core("Sega Mega Drive / Genesis")
endif()
if(saturn IN_LIST ARES_CORES)
enable_core("Sega Saturn")
add_subdirectory(saturn)
else()
disable_core("Sega Saturn")
endif()
if(ps1 IN_LIST ARES_CORES)
enable_core("PlayStation")
add_subdirectory(ps1)
else()
disable_core("Playstation")
endif()
if(pce IN_LIST ARES_CORES)
enable_core("PC-Engine / TurboGrafx")
add_subdirectory(pce)
else()
disable_core("PC-Engine / TurboGrafx")
endif()
if(msx IN_LIST ARES_CORES)
enable_core("Microsoft MSX")
add_subdirectory(msx)
else()
disable_core("Microsoft MSX")
endif()
if(cv IN_LIST ARES_CORES)
enable_core("ColecoVision")
add_subdirectory(cv)
else()
disable_core("ColecoVision")
endif()
if(myvision IN_LIST ARES_CORES)
enable_core("My Vision")
add_subdirectory(myvision)
else()
disable_core("My Vision")
endif()
if(gb IN_LIST ARES_CORES)
enable_core("Game Boy / Game Boy Color")
add_subdirectory(gb)
else()
disable_core("Game Boy / Game Boy Color")
endif()
if(gba IN_LIST ARES_CORES)
enable_core("Game Boy Advance")
add_subdirectory(gba)
else()
disable_core("Game Boy Advance")
endif()
if(ws IN_LIST ARES_CORES)
enable_core("WonderSwan / WonderSwan Color")
add_subdirectory(ws)
else()
disable_core("WonderSwan / WonderSwan Color")
endif()
if(ng IN_LIST ARES_CORES)
enable_core("Neo Geo (AES/MVS)")
add_subdirectory(ng)
else()
disable_core("Neo Geo (AES/MVS)")
endif()
if(ngp IN_LIST ARES_CORES)
enable_core("Neo Geo Pocket / Neo Geo Pocket Color")
add_subdirectory(ngp)
else()
disable_core("Neo Geo Pocket / Neo Geo Pocket Color")
endif()
if(spec IN_LIST ARES_CORES)
enable_core("ZX Spectrum")
add_subdirectory(spec)
else()
disable_core("ZX Spectrum")
endif()
add_subdirectory(component)
foreach(c IN LISTS ARES_CORES)
# target_enable_feature(ares "${c} core" CORE_$<UPPER_CASE:${c}>)
target_compile_definitions(ares PUBLIC CORE_$<UPPER_CASE:${c}>)
endforeach()
get_target_property(ares_SOURCES ares SOURCES)
set_source_files_properties(
ares
ares/debug/debug.cpp
ares/node/audio/stream.cpp
ares/node/node.cpp
ares/node/video/screen.cpp
ares/node/video/sprite.cpp
ares/scheduler/thread.cpp
ares/scheduler/scheduler.cpp
PROPERTIES HEADER_FILE_ONLY TRUE
)
set_source_files_properties(
n64/vulkan/parallel-rdp/vulkan/shader.cpp
n64/vulkan/parallel-rdp/vulkan/descriptor_set.cpp
n64/vulkan/parallel-rdp/vulkan/device.cpp
n64/vulkan/parallel-rdp/vulkan/command_buffer.cpp
n64/vulkan/parallel-rdp/vulkan/render_pass.cpp
PROPERTIES SKIP_PRECOMPILE_HEADERS ON
)
target_sources(ares PRIVATE cmake/os-macos.cmake cmake/os-windows.cmake cmake/os-linux.cmake)
set_source_files_properties(ares ${ARES_HEADER_SOURCES} PROPERTIES HEADER_FILE_ONLY TRUE)
set_source_files_properties(ares ares/ares.cpp ares/memory/fixed-allocator.cpp PROPERTIES HEADER_FILE_ONLY FALSE)
target_include_directories(ares INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${ares_SOURCES})
+98
View File
@@ -0,0 +1,98 @@
ares_components(mos6502)
ares_add_sources(
CORE #
a26
UNITY #
a26.cpp
PRIMARY #
system/system.cpp
controller/controller.cpp
cartridge/cartridge.cpp
cpu/cpu.cpp
tia/tia.cpp
riot/riot.cpp
)
ares_add_sources(
CORE #
a26
INCLUDED #
a26.hpp
CMakeLists.txt
)
ares_add_sources(
CORE #
a26
INCLUDED #
cartridge/cartridge.hpp
cartridge/serialization.cpp
cartridge/slot.cpp
cartridge/slot.hpp
cartridge/board/atari16k.cpp
cartridge/board/atari32k.cpp
cartridge/board/atari8k.cpp
cartridge/board/board.cpp
cartridge/board/board.hpp
cartridge/board/commavid.cpp
cartridge/board/linear.cpp
cartridge/board/parker-bros.cpp
cartridge/board/tigervision.cpp
)
ares_add_sources(
CORE #
a26
INCLUDED #
controller/controller.hpp
controller/port.cpp
controller/port.hpp
controller/gamepad/gamepad.cpp
controller/gamepad/gamepad.hpp
)
ares_add_sources(
CORE #
a26
INCLUDED #
cpu/cpu.hpp
cpu/debugger.cpp
cpu/memory.cpp
cpu/serialization.cpp
cpu/timing.cpp
)
ares_add_sources(
CORE #
a26
INCLUDED #
riot/io.cpp
riot/riot.hpp
riot/serialization.cpp
)
ares_add_sources(
CORE #
a26
INCLUDED #
system/controls.cpp
system/serialization.cpp
system/system.hpp
)
ares_add_sources(
CORE #
a26
INCLUDED #
tia/audio.cpp
tia/ball.cpp
tia/color.cpp
tia/io.cpp
tia/missile.cpp
tia/player.cpp
tia/playfield.cpp
tia/serialization.cpp
tia/tia.hpp
tia/write-queue.cpp
)
+7
View File
@@ -0,0 +1,7 @@
#include <a26/cartridge/cartridge.cpp>
#include <a26/controller/controller.cpp>
#include <a26/cpu/cpu.cpp>
#include <a26/riot/riot.cpp>
#include <a26/system/system.cpp>
#include <a26/tia/tia.cpp>
+1 -1
View File
@@ -10,7 +10,7 @@ Platform* platform = nullptr;
bool _runAhead = false;
const string Name = "ares";
const string Version = "140";
const string Version = "142";
const string Copyright = "ares team, Near";
const string License = "ISC";
const string LicenseURI = "https://opensource.org/licenses/ISC";
+1 -1
View File
@@ -15,6 +15,7 @@
#include <nall/endian.hpp>
#include <nall/hashset.hpp>
#include <nall/image.hpp>
#include <nall/instruction-set.hpp>
#include <nall/literals.hpp>
#include <nall/priority-queue.hpp>
#include <nall/queue.hpp>
@@ -78,4 +79,3 @@ namespace ares {
#include <ares/memory/fixed-allocator.hpp>
#include <ares/memory/readable.hpp>
#include <ares/memory/writable.hpp>
#include <ares/resource/resource.hpp>
+1 -1
View File
@@ -6,7 +6,7 @@
namespace ares::Memory {
constexpr u32 fixedBufferSize = 128_MiB;
constexpr u32 fixedBufferSize = 64_MiB;
#if defined(STATIC_ALLOCATION)
u8 fixedBuffer[fixedBufferSize + 64_KiB];
+1 -1
View File
@@ -83,7 +83,7 @@ protected:
f64 _luminance = 1.0;
u32 _fillColor = 0;
bool _colorBleed = false;
bool _colorBleedWidth = 1;
u32 _colorBleedWidth = 1;
bool _interframeBlending = false;
bool _overscan = true;
u32 _rotation = 0; //counter-clockwise (90 = left, 270 = right)
+3
View File
@@ -0,0 +1,3 @@
target_link_options(ares PRIVATE LINKER:-export-dynamic)
target_sources(ares PRIVATE cmake/os-linux.cmake)
+1
View File
@@ -0,0 +1 @@
target_sources(ares PRIVATE cmake/os-macos.cmake)
+5
View File
@@ -0,0 +1,5 @@
target_link_libraries(
ares
PRIVATE uuid kernel32 user32 gdi32 comctl32 comdlg32 shell32
)
target_sources(ares PRIVATE cmake/os-windows.cmake)
+471
View File
@@ -0,0 +1,471 @@
list(REMOVE_DUPLICATES ares.components)
ares_add_sources(INCLUDED CMakeLists.txt)
macro(component_sources)
set(options "")
set(oneValueArgs COMPONENT PRIMARY)
set(multiValueArgs INCLUDED)
cmake_parse_arguments(CPS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(${CPS_COMPONENT} IN_LIST ares.components)
target_sources(ares PRIVATE ${CPS_PRIMARY})
foreach(arg IN ITEMS ${CPS_INCLUDED})
list(APPEND ARES_HEADER_SOURCES "component/${arg}")
target_sources(ares PRIVATE ${arg})
endforeach()
endif()
set(ARES_HEADER_SOURCES ${ARES_HEADER_SOURCES} PARENT_SCOPE)
endmacro()
component_sources(
COMPONENT
ay38910
PRIMARY
audio/ay38910/ay38910.cpp
INCLUDED
audio/ay38910/ay38910.hpp
audio/ay38910/serialization.cpp
)
component_sources(
COMPONENT
msm5205
PRIMARY
audio/msm5205/msm5205.cpp
INCLUDED
audio/msm5205/msm5205.hpp
audio/msm5205/serialization.cpp
)
component_sources(
COMPONENT
sn76489
PRIMARY
audio/sn76489/sn76489.cpp
INCLUDED
audio/sn76489/sn76489.hpp
audio/sn76489/serialization.cpp
)
component_sources(
COMPONENT
t6w28
PRIMARY
audio/t6w28/t6w28.cpp
INCLUDED
audio/t6w28/t6w28.hpp
audio/t6w28/serialization.cpp
)
component_sources(
COMPONENT
ym2149
PRIMARY
audio/ym2149/ym2149.cpp
INCLUDED
audio/ym2149/ym2149.hpp
audio/ym2149/serialization.cpp
)
component_sources(
COMPONENT
ym2413
PRIMARY
audio/ym2413/ym2413.cpp
INCLUDED
audio/ym2413/constants.cpp
audio/ym2413/io.cpp
audio/ym2413/operator.cpp
audio/ym2413/serialization.cpp
audio/ym2413/voice.cpp
audio/ym2413/ym2413.hpp
)
component_sources(
COMPONENT
ym2612
PRIMARY
audio/ym2612/ym2612.cpp
INCLUDED
audio/ym2612/channel.cpp
audio/ym2612/constants.cpp
audio/ym2612/io.cpp
audio/ym2612/serialization.cpp
audio/ym2612/timer.cpp
audio/ym2612/ym2612.hpp
)
component_sources(
COMPONENT
m24c
PRIMARY
eeprom/m24c/m24c.cpp
INCLUDED
eeprom/m24c/m24c.hpp
eeprom/m24c/serialization.cpp
)
component_sources(
COMPONENT
m93lcx6
PRIMARY
eeprom/m93lcx6/m93lcx6.cpp
INCLUDED
eeprom/m93lcx6/m93lcx6.hpp
eeprom/m93lcx6/serialization.cpp
)
component_sources(
COMPONENT
i8255
PRIMARY
io/i8255/i8255.cpp
INCLUDED
io/i8255/i8255.hpp
)
component_sources(
COMPONENT
arm7tdmi
PRIMARY
processor/arm7tdmi/arm7tdmi.cpp
INCLUDED
processor/arm7tdmi/algorithms.cpp
processor/arm7tdmi/arm7tdmi.hpp
processor/arm7tdmi/disassembler.cpp
processor/arm7tdmi/instruction.cpp
processor/arm7tdmi/instructions-arm.cpp
processor/arm7tdmi/instructions-thumb.cpp
processor/arm7tdmi/memory.cpp
processor/arm7tdmi/registers.cpp
processor/arm7tdmi/serialization.cpp
)
component_sources(
COMPONENT
gsu
PRIMARY
processor/gsu/gsu.cpp
INCLUDED
processor/gsu/disassembler.cpp
processor/gsu/gsu.hpp
processor/gsu/instruction.cpp
processor/gsu/instructions.cpp
processor/gsu/registers.hpp
processor/gsu/serialization.cpp
)
component_sources(
COMPONENT
hg51b
PRIMARY
processor/hg51b/hg51b.cpp
INCLUDED
processor/hg51b/disassembler.cpp
processor/hg51b/hg51b.hpp
processor/hg51b/instruction.cpp
processor/hg51b/instructions.cpp
processor/hg51b/registers.cpp
processor/hg51b/serialization.cpp
)
component_sources(
COMPONENT
huc6280
PRIMARY
processor/huc6280/huc6280.cpp
INCLUDED
processor/huc6280/algorithms.cpp
processor/huc6280/disassembler.cpp
processor/huc6280/huc6280.hpp
processor/huc6280/instruction.cpp
processor/huc6280/instructions.cpp
processor/huc6280/memory.cpp
processor/huc6280/serialization.cpp
)
component_sources(
COMPONENT
i8080
PRIMARY
processor/i8080/i8080.cpp
INCLUDED
processor/i8080/algorithms.cpp
processor/i8080/disassembler.cpp
processor/i8080/i8080.hpp
processor/i8080/instruction.cpp
processor/i8080/instructions.cpp
processor/i8080/memory.cpp
processor/i8080/registers.hpp
processor/i8080/serialization.cpp
)
component_sources(
COMPONENT
m68hc05
PRIMARY
processor/m68hc05/m68hc05.cpp
INCLUDED
processor/m68hc05/algorithms.cpp
processor/m68hc05/disassembler.cpp
processor/m68hc05/instruction.cpp
processor/m68hc05/instructions.cpp
processor/m68hc05/m68hc05.hpp
processor/m68hc05/memory.cpp
processor/m68hc05/serialization.cpp
)
component_sources(
COMPONENT
m68000
PRIMARY
processor/m68000/m68000.cpp
INCLUDED
processor/m68000/algorithms.cpp
processor/m68000/conditions.cpp
processor/m68000/disassembler.cpp
processor/m68000/effective-address.cpp
processor/m68000/instruction.cpp
processor/m68000/instructions.cpp
processor/m68000/m68000.hpp
processor/m68000/memory.cpp
processor/m68000/registers.cpp
processor/m68000/serialization.cpp
processor/m68000/traits.cpp
)
component_sources(
COMPONENT
mos6502
PRIMARY
processor/mos6502/mos6502.cpp
INCLUDED
processor/mos6502/addresses.cpp
processor/mos6502/algorithms.cpp
processor/mos6502/disassembler.cpp
processor/mos6502/instruction.cpp
processor/mos6502/instructions.cpp
processor/mos6502/memory.cpp
processor/mos6502/mos6502.hpp
processor/mos6502/serialization.cpp
)
component_sources(
COMPONENT
sh2
PRIMARY
processor/sh2/sh2.cpp
INCLUDED
processor/sh2/accuracy.hpp
processor/sh2/decoder.hpp
processor/sh2/disassembler.cpp
processor/sh2/exceptions.cpp
processor/sh2/instruction.cpp
processor/sh2/instructions.cpp
processor/sh2/recompiler.cpp
processor/sh2/serialization.cpp
processor/sh2/sh2.hpp
processor/sh2/sh7604/bus.cpp
processor/sh2/sh7604/cache.cpp
processor/sh2/sh7604/dma.cpp
processor/sh2/sh7604/interrupts.cpp
processor/sh2/sh7604/io.cpp
processor/sh2/sh7604/serial.cpp
processor/sh2/sh7604/sh7604.cpp
processor/sh2/sh7604/sh7604.hpp
processor/sh2/sh7604/timer.cpp
)
component_sources(
COMPONENT
sm5k
PRIMARY
processor/sm5k/sm5k.cpp
INCLUDED
processor/sm5k/disassembler.cpp
processor/sm5k/instruction.cpp
processor/sm5k/instructions.cpp
processor/sm5k/memory.cpp
processor/sm5k/serialization.cpp
processor/sm5k/sm5k.hpp
processor/sm5k/timer.cpp
)
component_sources(
COMPONENT
sm83
PRIMARY
processor/sm83/sm83.cpp
INCLUDED
processor/sm83/algorithms.cpp
processor/sm83/disassembler.cpp
processor/sm83/instruction.cpp
processor/sm83/instructions.cpp
processor/sm83/memory.cpp
processor/sm83/registers.hpp
processor/sm83/serialization.cpp
processor/sm83/sm83.hpp
)
component_sources(
COMPONENT
spc700
PRIMARY
processor/spc700/spc700.cpp
INCLUDED
processor/spc700/algorithms.cpp
processor/spc700/disassembler.cpp
processor/spc700/instruction.cpp
processor/spc700/instructions.cpp
processor/spc700/memory.cpp
processor/spc700/serialization.cpp
processor/spc700/spc700.hpp
)
component_sources(
COMPONENT
ssp1601
PRIMARY
processor/ssp1601/ssp1601.cpp
INCLUDED
processor/ssp1601/algorithms.cpp
processor/ssp1601/disassembler.cpp
processor/ssp1601/instructions.cpp
processor/ssp1601/memory.cpp
processor/ssp1601/registers.cpp
processor/ssp1601/serialization.cpp
processor/ssp1601/ssp1601.hpp
)
component_sources(
COMPONENT
tlcs900h
PRIMARY
processor/tlcs900h/tlcs900h.cpp
INCLUDED
processor/tlcs900h/algorithms.cpp
processor/tlcs900h/conditions.cpp
processor/tlcs900h/control-registers.cpp
processor/tlcs900h/disassembler.cpp
processor/tlcs900h/dma.cpp
processor/tlcs900h/instruction.cpp
processor/tlcs900h/instructions.cpp
processor/tlcs900h/memory.cpp
processor/tlcs900h/prefetch.cpp
processor/tlcs900h/registers.cpp
processor/tlcs900h/serialization.cpp
processor/tlcs900h/tlcs900h.hpp
)
component_sources(
COMPONENT
upd96050
PRIMARY
processor/upd96050/upd96050.cpp
INCLUDED
processor/upd96050/disassembler.cpp
processor/upd96050/instructions.cpp
processor/upd96050/memory.cpp
processor/upd96050/serialization.cpp
processor/upd96050/upd96050.hpp
)
component_sources(
COMPONENT
v30mz
PRIMARY
processor/v30mz/v30mz.cpp
INCLUDED
processor/v30mz/algorithms.cpp
processor/v30mz/disassembler.cpp
processor/v30mz/instruction.cpp
processor/v30mz/instructions-adjust.cpp
processor/v30mz/instructions-alu.cpp
processor/v30mz/instructions-exec.cpp
processor/v30mz/instructions-flag.cpp
processor/v30mz/instructions-group.cpp
processor/v30mz/instructions-misc.cpp
processor/v30mz/instructions-move.cpp
processor/v30mz/instructions-string.cpp
processor/v30mz/memory.cpp
processor/v30mz/modrm.cpp
processor/v30mz/prefetch.cpp
processor/v30mz/registers.cpp
processor/v30mz/serialization.cpp
processor/v30mz/v30mz.hpp
)
component_sources(
COMPONENT
wdc65816
PRIMARY
processor/wdc65816/wdc65816.cpp
INCLUDED
processor/wdc65816/algorithms.cpp
processor/wdc65816/disassembler.cpp
processor/wdc65816/instruction.cpp
processor/wdc65816/instruction.hpp
processor/wdc65816/instructions-modify.cpp
processor/wdc65816/instructions-other.cpp
processor/wdc65816/instructions-pc.cpp
processor/wdc65816/instructions-read.cpp
processor/wdc65816/instructions-write.cpp
processor/wdc65816/memory.cpp
processor/wdc65816/registers.hpp
processor/wdc65816/serialization.cpp
processor/wdc65816/wdc65816.hpp
)
component_sources(
COMPONENT
z80
PRIMARY
processor/z80/z80.cpp
INCLUDED
processor/z80/algorithms.cpp
processor/z80/disassembler.cpp
processor/z80/instruction.cpp
processor/z80/instructions.cpp
processor/z80/memory.cpp
processor/z80/registers.hpp
processor/z80/serialization.cpp
processor/z80/z80.hpp
)
component_sources(
COMPONENT
sst39sf0x0
PRIMARY
flash/sst39sf0x0/sst39sf0x0.cpp
INCLUDED
flash/sst39sf0x0/sst39sf0x0.hpp
)
component_sources(
COMPONENT
tms9918
PRIMARY
video/tms9918/tms9918.cpp
INCLUDED
video/tms9918/background.cpp
video/tms9918/dac.cpp
video/tms9918/io.cpp
video/tms9918/serialization.cpp
video/tms9918/sprite.cpp
video/tms9918/tms9918.hpp
)
component_sources(
COMPONENT
v9938
PRIMARY
video/v9938/v9938.cpp
INCLUDED
video/v9938/background.cpp
video/v9938/commands.cpp
video/v9938/dac.cpp
video/v9938/io.cpp
video/v9938/serialization.cpp
video/v9938/sprite.cpp
video/v9938/v9938.hpp
)
+21 -21
View File
@@ -29,24 +29,25 @@ auto YM2612::Channel::Operator::updateKeyState() -> void {
auto YM2612::Channel::Operator::runEnvelope() -> void {
if(ym2612.envelope.clock & (1 << envelope.divider) - 1) return;
if(envelope.state == Attack && envelope.value == 0) {
envelope.state = Decay;
updateEnvelope();
}
u32 sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x1f << 5;
if(envelope.state == Decay && envelope.value >= sustain) {
envelope.state = Sustain;
updateEnvelope();
}
u32 value = ym2612.envelope.clock >> envelope.divider;
u32 step = envelope.steps >> ((~value & 7) << 2) & 0xf;
u32 sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x1f << 5;
if(envelope.state == Attack) {
if(envelope.value == 0) {
envelope.state = Decay;
updateEnvelope();
} else if(envelope.rate < 62) {
// will stop updating if attack rate is increased to upper threshold during attack phase (confirmed behavior)
envelope.value += ~u16(envelope.value) * step >> 4;
}
// will stop updating if attack rate is increased to upper threshold during attack phase (confirmed behavior)
if(envelope.rate < 62) envelope.value += ~u16(envelope.value) * step >> 4;
}
if(envelope.state != Attack) {
if(envelope.state == Decay && envelope.value >= sustain) {
envelope.state = Sustain;
updateEnvelope();
}
if(ssg.enable) step = envelope.value < 0x200 ? step << 2 : 0; //SSG results in a 4x faster envelope
envelope.value = min(envelope.value + step, 0x3ff);
}
@@ -82,8 +83,6 @@ auto YM2612::Channel::Operator::runPhase() -> void {
}
auto YM2612::Channel::Operator::updateEnvelope() -> void {
u32 key = min(max((u32)pitch.value, 0x300), 0x4ff);
u32 ksr = (octave.value << 2) + ((key - 0x300) >> 7);
u32 rate = 0;
if(envelope.state == Attack) rate += (envelope.attackRate << 1);
@@ -91,7 +90,7 @@ auto YM2612::Channel::Operator::updateEnvelope() -> void {
if(envelope.state == Sustain) rate += (envelope.sustainRate << 1);
if(envelope.state == Release) rate += (envelope.releaseRate << 1);
rate += (ksr >> 3 - envelope.keyScale) * (rate > 0);
rate += (keyScale >> 3 - envelope.rateScaling) * (rate > 0);
rate = min(rate, 63);
auto& entry = envelopeRates[rate >> 2];
@@ -107,15 +106,15 @@ auto YM2612::Channel::Operator::updatePitch() -> void {
pitch.value = channel.mode ? pitch.reload : channel[3].pitch.reload;
octave.value = channel.mode ? octave.reload : channel[3].octave.reload;
u32 key = min(max((u32)pitch.value, 0x300), 0x4ff);
keyScale = (octave.value << 2) + ((key - 0x300) >> 7);
updatePhase();
updateEnvelope(); //due to key scaling
}
auto YM2612::Channel::Operator::updatePhase() -> void {
u32 key = min(max((u32)pitch.value, 0x300), 0x4ff);
u32 ksr = (octave.value << 2) + ((key - 0x300) >> 7);
u32 tuning = detune & 3 ? detunes[(detune & 3) - 1][ksr & 7] >> (3 - (ksr >> 3)) : 0;
u32 tuning = detune & 3 ? detunes[(detune & 3) - 1][keyScale & 7] >> (3 - (keyScale >> 3)) : 0;
u32 lfo = ym2612.lfo.clock >> 2 & 0x1f;
s32 pm = (pitch.value * vibratos[channel.vibrato][lfo & 15] >> 9) * (lfo > 15 ? -1 : 1);
@@ -131,7 +130,7 @@ auto YM2612::Channel::Operator::updateLevel() -> void {
bool invert = ssg.attack != ssg.invert && envelope.state != Release;
n10 value = ssg.enable && invert ? 0x200 - envelope.value : 0 + envelope.value;
outputLevel = ((totalLevel << 3) + value + (lfoEnable ? lfo << 1 >> depth : 0)) << 3;
outputLevel = (totalLevel << 3) + value + (lfo << 1 >> depth) << 3;
}
auto YM2612::Channel::power() -> void {
@@ -149,6 +148,7 @@ auto YM2612::Channel::power() -> void {
op.keyOn = 0;
op.keyLine = 0;
op.lfoEnable = 0;
op.keyScale = 0;
op.detune = 0;
op.multiple = 0;
op.totalLevel = 0;
@@ -175,7 +175,7 @@ auto YM2612::Channel::power() -> void {
op.envelope.steps = 0;
op.envelope.value = 0x3ff;
op.envelope.keyScale = 0;
op.envelope.rateScaling = 0;
op.envelope.attackRate = 0;
op.envelope.decayRate = 0;
op.envelope.sustainRate = 0;
+6 -4
View File
@@ -14,8 +14,10 @@ auto YM2612::writeData(n8 data) -> void {
case 0x022: {
lfo.rate = data.bit(0,2);
lfo.enable = data.bit(3);
lfo.clock = 0;
lfo.divider = 0;
if(!lfo.enable) {
lfo.clock = 0;
lfo.divider = 0;
}
break;
}
@@ -114,10 +116,10 @@ auto YM2612::writeData(n8 data) -> void {
break;
}
//key scaling, attack rate
//rate scaling, attack rate
case 0x050: {
op.envelope.attackRate = data.bit(0,4);
op.envelope.keyScale = data.bit(6,7);
op.envelope.rateScaling = data.bit(6,7);
channel[index].updateEnvelope();
channel[index].updatePhase();
break;
@@ -44,6 +44,7 @@ auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
s(keyOn);
s(keyLine);
s(lfoEnable);
s(keyScale);
s(detune);
s(multiple);
s(totalLevel);
@@ -68,7 +69,7 @@ auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
s(envelope.divider);
s(envelope.steps);
s(envelope.value);
s(envelope.keyScale);
s(envelope.rateScaling);
s(envelope.attackRate);
s(envelope.decayRate);
s(envelope.sustainRate);
+28 -30
View File
@@ -13,6 +13,25 @@ auto YM2612::clock() -> array<i16[2]> {
s32 left = 0;
s32 right = 0;
timerA.run();
timerB.run();
if(++envelope.divider == 3) {
envelope.divider = 0;
if(!++envelope.clock) ++envelope.clock; // 12-bit counter: 1..4095 - zero-value is skipped (confirmed behavior)
}
if(lfo.enable && ++lfo.divider >= lfoDividers[lfo.rate]) {
lfo.divider = 0;
lfo.clock++;
for(auto& channel : channels) {
for(auto& op : channel.operators) {
op.updatePhase(); //due to vibrato
op.updateLevel(); //due to tremolo
}
}
}
for(auto& channel : channels) {
auto& op = channel.operators;
@@ -30,12 +49,18 @@ auto YM2612::clock() -> array<i16[2]> {
return y < 0x1a00 ? pow2[y & 0x1ff] << 2 >> (y >> 9) : 0; // -78 dB floor
};
s32 feedback = modMask & op[0].prior + op[0].priorBuffer >> 9 - channel.feedback;
s32 accumulator = 0;
op[0].priorBuffer = op[0].prior; // only need to buffer the output for feedback
for(auto n : range(4)) op[n].prior = op[n].output;
for(auto& op : channel.operators) {
op.runPhase();
if(envelope.divider) continue;
op.runEnvelope();
}
s32 feedback = modMask & op[0].prior + op[0].priorBuffer >> 9 - channel.feedback;
s32 accumulator = 0;
op[0].output = wave(0, feedback * (channel.feedback > 0));
// Note: Despite not emulating per cycle, operator pipelining has been accounted for.
@@ -122,33 +147,6 @@ auto YM2612::clock() -> array<i16[2]> {
//if(channel.rightEnable) right += voiceData;
}
timerA.run();
timerB.run();
if(lfo.enable && ++lfo.divider == lfoDividers[lfo.rate]) {
lfo.divider = 0;
lfo.clock++;
for(auto& channel : channels) {
for(auto& op : channel.operators) {
op.updatePhase(); //due to vibrato
op.updateLevel(); //due to tremolo
}
}
}
if(++envelope.divider == 3) {
envelope.divider = 0;
if(!++envelope.clock) ++envelope.clock; // 12-bit counter: 1..4095 - zero-value is skipped (confirmed behavior)
}
for(auto& channel : channels) {
for(auto& op : channel.operators) {
op.runPhase();
if(envelope.divider) continue;
op.runEnvelope();
}
}
return {sclamp<16>(left), sclamp<16>(right)};
}
+2 -1
View File
@@ -107,6 +107,7 @@ protected:
n1 keyOn = 0;
n1 keyLine = 0;
n1 lfoEnable = 0;
n5 keyScale = 0;
n3 detune = 0;
n4 multiple = 0;
n7 totalLevel = 0;
@@ -140,7 +141,7 @@ protected:
n32 steps = 0;
n10 value = 0x3ff;
n2 keyScale = 0;
n2 rateScaling = 0;
n5 attackRate = 0;
n5 decayRate = 0;
n5 sustainRate = 0;
@@ -22,6 +22,8 @@ struct ARM7TDMI {
virtual auto get(u32 mode, n32 address) -> n32 = 0;
virtual auto getDebugger(u32 mode, n32 address) -> n32 { return get(mode, address); }
virtual auto set(u32 mode, n32 address, n32 word) -> void = 0;
virtual auto lock() -> void { return; }
virtual auto unlock() -> void { return; }
//arm7tdmi.cpp
ARM7TDMI();
@@ -56,6 +58,7 @@ struct ARM7TDMI {
auto TST(n4) -> bool;
//instruction.cpp
auto reload() -> void;
auto fetch() -> void;
auto instruction() -> void;
auto exception(u32 mode, n32 address) -> void;
@@ -214,6 +217,7 @@ struct ARM7TDMI {
n32 address;
n32 instruction;
b1 thumb; //not used by fetch stage
b1 irq; //not used by fetch stage
};
n1 reload = 1;
@@ -1,7 +1,20 @@
auto ARM7TDMI::reload() -> void {
u32 mask = !cpsr().t ? 3 : 1;
u32 size = !cpsr().t ? Word : Half;
pipeline.reload = false;
r(15).data &= ~mask;
pipeline.fetch.address = r(15) & ~mask;
pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address);
fetch();
}
auto ARM7TDMI::fetch() -> void {
pipeline.execute = pipeline.decode;
pipeline.execute.irq = pipeline.execute.irq & irq;
pipeline.decode = pipeline.fetch;
pipeline.decode.thumb = cpsr().t;
pipeline.decode.irq = !cpsr().i;
u32 sequential = Sequential;
if(pipeline.nonsequential) {
@@ -18,19 +31,10 @@ auto ARM7TDMI::fetch() -> void {
}
auto ARM7TDMI::instruction() -> void {
u32 mask = !cpsr().t ? 3 : 1;
u32 size = !cpsr().t ? Word : Half;
if(pipeline.reload) {
pipeline.reload = false;
r(15).data &= ~mask;
pipeline.fetch.address = r(15) & ~mask;
pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address);
fetch();
}
if(pipeline.reload) reload();
fetch();
if(irq && !cpsr().i) {
if(pipeline.execute.irq) {
exception(PSR::IRQ, 0x18);
if(pipeline.execute.thumb) r(14).data += 2;
return;
@@ -419,9 +423,9 @@ auto ARM7TDMI::thumbInitialize() -> void {
bind(opcode, AdjustStack, immediate, mode);
}
for(n3 _ : range(8))
for(n4 d : range(16))
for(n4 m : range(16)) {
auto opcode = pattern("0100 0111 0??? ?---") | _ << 0 | m << 3;
auto opcode = pattern("0100 0111 ???? ?---") | d.bit(0,2) << 0 | m << 3 | d.bit(3) << 7;
bind(opcode, BranchExchange, m);
}
@@ -131,9 +131,11 @@ auto ARM7TDMI::armInstructionLoadRegister
auto ARM7TDMI::armInstructionMemorySwap
(n4 m, n4 d, n4 n, n1 byte) -> void {
lock();
n32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
r(d) = word;
unlock();
}
auto ARM7TDMI::armInstructionMoveHalfImmediate
@@ -300,8 +302,8 @@ auto ARM7TDMI::armInstructionMultiplyLong
n64 rd = rm * rs;
if(accumulate) rd += (n64)r(h) << 32 | (n64)r(l) << 0;
r(h) = rd >> 32;
r(l) = rd >> 0;
r(h) = rd >> 32;
if(save) {
cpsr().z = rd == 0;
@@ -62,10 +62,13 @@ auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
s(fetch.address);
s(fetch.instruction);
s(fetch.thumb);
s(fetch.irq);
s(decode.address);
s(decode.instruction);
s(decode.thumb);
s(decode.irq);
s(execute.address);
s(execute.instruction);
s(execute.thumb);
s(execute.irq);
}
+200 -200
View File
@@ -37,56 +37,56 @@ auto GSU::disassembleOpcode(char* output) -> void {
auto GSU::disassembleALT0(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (s8)op1); break;
case (0x06): sprintf(t, "blt %+d", (s8)op1); break;
case (0x07): sprintf(t, "bge %+d", (s8)op1); break;
case (0x08): sprintf(t, "bne %+d", (s8)op1); break;
case (0x09): sprintf(t, "beq %+d", (s8)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (s8)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (s8)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (s8)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (s8)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (s8)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (s8)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "plot"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "color"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "add r%u", op0 & 15); break;
case16(0x60): sprintf(t, "sub r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "and r%u", op0 & 15); break;
case16(0x80): sprintf(t, "mult r%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "asr"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "fmult"); break;
case16(0xa0): sprintf(t, "ibt r%u,#$%.2x", op0 & 15, op1 & 255); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "or r%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "getc"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getb"); break;
case16(0xf0): sprintf(t, "iwt r%u,#$%.2x%.2x", op0 & 15, op2 & 255, op1 & 255); break;
case (0x00):snprintf(t, sizeof(t), "stop"); break;
case (0x01):snprintf(t, sizeof(t), "nop"); break;
case (0x02):snprintf(t, sizeof(t), "cache"); break;
case (0x03):snprintf(t, sizeof(t), "lsr"); break;
case (0x04):snprintf(t, sizeof(t), "rol"); break;
case (0x05):snprintf(t, sizeof(t), "bra %+d", (s8)op1); break;
case (0x06):snprintf(t, sizeof(t), "blt %+d", (s8)op1); break;
case (0x07):snprintf(t, sizeof(t), "bge %+d", (s8)op1); break;
case (0x08):snprintf(t, sizeof(t), "bne %+d", (s8)op1); break;
case (0x09):snprintf(t, sizeof(t), "beq %+d", (s8)op1); break;
case (0x0a):snprintf(t, sizeof(t), "bpl %+d", (s8)op1); break;
case (0x0b):snprintf(t, sizeof(t), "bmi %+d", (s8)op1); break;
case (0x0c):snprintf(t, sizeof(t), "bcc %+d", (s8)op1); break;
case (0x0d):snprintf(t, sizeof(t), "bcs %+d", (s8)op1); break;
case (0x0e):snprintf(t, sizeof(t), "bvc %+d", (s8)op1); break;
case (0x0f):snprintf(t, sizeof(t), "bvs %+d", (s8)op1); break;
case16(0x10):snprintf(t, sizeof(t), "to r%u", op0 & 15); break;
case16(0x20):snprintf(t, sizeof(t), "with r%u", op0 & 15); break;
case12(0x30):snprintf(t, sizeof(t), "stw (r%u)", op0 & 15); break;
case (0x3c):snprintf(t, sizeof(t), "loop"); break;
case (0x3d):snprintf(t, sizeof(t), "alt1"); break;
case (0x3e):snprintf(t, sizeof(t), "alt2"); break;
case (0x3f):snprintf(t, sizeof(t), "alt3"); break;
case12(0x40):snprintf(t, sizeof(t), "ldw (r%u)", op0 & 15); break;
case (0x4c):snprintf(t, sizeof(t), "plot"); break;
case (0x4d):snprintf(t, sizeof(t), "swap"); break;
case (0x4e):snprintf(t, sizeof(t), "color"); break;
case (0x4f):snprintf(t, sizeof(t), "not"); break;
case16(0x50):snprintf(t, sizeof(t), "add r%u", op0 & 15); break;
case16(0x60):snprintf(t, sizeof(t), "sub r%u", op0 & 15); break;
case (0x70):snprintf(t, sizeof(t), "merge"); break;
case15(0x71):snprintf(t, sizeof(t), "and r%u", op0 & 15); break;
case16(0x80):snprintf(t, sizeof(t), "mult r%u", op0 & 15); break;
case (0x90):snprintf(t, sizeof(t), "sbk"); break;
case4 (0x91):snprintf(t, sizeof(t), "link #%u", op0 & 15); break;
case (0x95):snprintf(t, sizeof(t), "sex"); break;
case (0x96):snprintf(t, sizeof(t), "asr"); break;
case (0x97):snprintf(t, sizeof(t), "ror"); break;
case6 (0x98):snprintf(t, sizeof(t), "jmp r%u", op0 & 15); break;
case (0x9e):snprintf(t, sizeof(t), "lob"); break;
case (0x9f):snprintf(t, sizeof(t), "fmult"); break;
case16(0xa0):snprintf(t, sizeof(t), "ibt r%u,#$%.2x", op0 & 15, op1 & 255); break;
case16(0xb0):snprintf(t, sizeof(t), "from r%u", op0 & 15); break;
case (0xc0):snprintf(t, sizeof(t), "hib"); break;
case15(0xc1):snprintf(t, sizeof(t), "or r%u", op0 & 15); break;
case15(0xd0):snprintf(t, sizeof(t), "inc r%u", op0 & 15); break;
case (0xdf):snprintf(t, sizeof(t), "getc"); break;
case15(0xe0):snprintf(t, sizeof(t), "dec r%u", op0 & 15); break;
case (0xef):snprintf(t, sizeof(t), "getb"); break;
case16(0xf0):snprintf(t, sizeof(t), "iwt r%u,#$%.2x%.2x", op0 & 15, op2 & 255, op1 & 255); break;
}
strcat(output, t);
}
@@ -94,56 +94,56 @@ auto GSU::disassembleALT0(char* output) -> void {
auto GSU::disassembleALT1(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (s8)op1); break;
case (0x06): sprintf(t, "blt %+d", (s8)op1); break;
case (0x07): sprintf(t, "bge %+d", (s8)op1); break;
case (0x08): sprintf(t, "bne %+d", (s8)op1); break;
case (0x09): sprintf(t, "beq %+d", (s8)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (s8)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (s8)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (s8)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (s8)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (s8)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (s8)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "rpix"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "cmode"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "adc r%u", op0 & 15); break;
case16(0x60): sprintf(t, "sbc r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "bic r%u", op0 & 15); break;
case16(0x80): sprintf(t, "umult r%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "div2"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "lmult"); break;
case16(0xa0): sprintf(t, "lms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "xor r%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "getc"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbh"); break;
case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break;
case (0x00):snprintf(t, sizeof(t), "stop"); break;
case (0x01):snprintf(t, sizeof(t), "nop"); break;
case (0x02):snprintf(t, sizeof(t), "cache"); break;
case (0x03):snprintf(t, sizeof(t), "lsr"); break;
case (0x04):snprintf(t, sizeof(t), "rol"); break;
case (0x05):snprintf(t, sizeof(t), "bra %+d", (s8)op1); break;
case (0x06):snprintf(t, sizeof(t), "blt %+d", (s8)op1); break;
case (0x07):snprintf(t, sizeof(t), "bge %+d", (s8)op1); break;
case (0x08):snprintf(t, sizeof(t), "bne %+d", (s8)op1); break;
case (0x09):snprintf(t, sizeof(t), "beq %+d", (s8)op1); break;
case (0x0a):snprintf(t, sizeof(t), "bpl %+d", (s8)op1); break;
case (0x0b):snprintf(t, sizeof(t), "bmi %+d", (s8)op1); break;
case (0x0c):snprintf(t, sizeof(t), "bcc %+d", (s8)op1); break;
case (0x0d):snprintf(t, sizeof(t), "bcs %+d", (s8)op1); break;
case (0x0e):snprintf(t, sizeof(t), "bvc %+d", (s8)op1); break;
case (0x0f):snprintf(t, sizeof(t), "bvs %+d", (s8)op1); break;
case16(0x10):snprintf(t, sizeof(t), "to r%u", op0 & 15); break;
case16(0x20):snprintf(t, sizeof(t), "with r%u", op0 & 15); break;
case12(0x30):snprintf(t, sizeof(t), "stb (r%u)", op0 & 15); break;
case (0x3c):snprintf(t, sizeof(t), "loop"); break;
case (0x3d):snprintf(t, sizeof(t), "alt1"); break;
case (0x3e):snprintf(t, sizeof(t), "alt2"); break;
case (0x3f):snprintf(t, sizeof(t), "alt3"); break;
case12(0x40):snprintf(t, sizeof(t), "ldb (r%u)", op0 & 15); break;
case (0x4c):snprintf(t, sizeof(t), "rpix"); break;
case (0x4d):snprintf(t, sizeof(t), "swap"); break;
case (0x4e):snprintf(t, sizeof(t), "cmode"); break;
case (0x4f):snprintf(t, sizeof(t), "not"); break;
case16(0x50):snprintf(t, sizeof(t), "adc r%u", op0 & 15); break;
case16(0x60):snprintf(t, sizeof(t), "sbc r%u", op0 & 15); break;
case (0x70):snprintf(t, sizeof(t), "merge"); break;
case15(0x71):snprintf(t, sizeof(t), "bic r%u", op0 & 15); break;
case16(0x80):snprintf(t, sizeof(t), "umult r%u", op0 & 15); break;
case (0x90):snprintf(t, sizeof(t), "sbk"); break;
case4 (0x91):snprintf(t, sizeof(t), "link #%u", op0 & 15); break;
case (0x95):snprintf(t, sizeof(t), "sex"); break;
case (0x96):snprintf(t, sizeof(t), "div2"); break;
case (0x97):snprintf(t, sizeof(t), "ror"); break;
case6 (0x98):snprintf(t, sizeof(t), "ljmp r%u", op0 & 15); break;
case (0x9e):snprintf(t, sizeof(t), "lob"); break;
case (0x9f):snprintf(t, sizeof(t), "lmult"); break;
case16(0xa0):snprintf(t, sizeof(t), "lms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
case16(0xb0):snprintf(t, sizeof(t), "from r%u", op0 & 15); break;
case (0xc0):snprintf(t, sizeof(t), "hib"); break;
case15(0xc1):snprintf(t, sizeof(t), "xor r%u", op0 & 15); break;
case15(0xd0):snprintf(t, sizeof(t), "inc r%u", op0 & 15); break;
case (0xdf):snprintf(t, sizeof(t), "getc"); break;
case15(0xe0):snprintf(t, sizeof(t), "dec r%u", op0 & 15); break;
case (0xef):snprintf(t, sizeof(t), "getbh"); break;
case16(0xf0):snprintf(t, sizeof(t), "lm r%u", op0 & 15); break;
}
strcat(output, t);
}
@@ -151,56 +151,56 @@ auto GSU::disassembleALT1(char* output) -> void {
auto GSU::disassembleALT2(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (s8)op1); break;
case (0x06): sprintf(t, "blt %+d", (s8)op1); break;
case (0x07): sprintf(t, "bge %+d", (s8)op1); break;
case (0x08): sprintf(t, "bne %+d", (s8)op1); break;
case (0x09): sprintf(t, "beq %+d", (s8)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (s8)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (s8)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (s8)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (s8)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (s8)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (s8)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "plot"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "color"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "add #%u", op0 & 15); break;
case16(0x60): sprintf(t, "sub #%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "and #%u", op0 & 15); break;
case16(0x80): sprintf(t, "mult #%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "asr"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "fmult"); break;
case16(0xa0): sprintf(t, "sms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "or #%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "ramb"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbl"); break;
case16(0xf0): sprintf(t, "sm r%u", op0 & 15); break;
case (0x00):snprintf(t, sizeof(t), "stop"); break;
case (0x01):snprintf(t, sizeof(t), "nop"); break;
case (0x02):snprintf(t, sizeof(t), "cache"); break;
case (0x03):snprintf(t, sizeof(t), "lsr"); break;
case (0x04):snprintf(t, sizeof(t), "rol"); break;
case (0x05):snprintf(t, sizeof(t), "bra %+d", (s8)op1); break;
case (0x06):snprintf(t, sizeof(t), "blt %+d", (s8)op1); break;
case (0x07):snprintf(t, sizeof(t), "bge %+d", (s8)op1); break;
case (0x08):snprintf(t, sizeof(t), "bne %+d", (s8)op1); break;
case (0x09):snprintf(t, sizeof(t), "beq %+d", (s8)op1); break;
case (0x0a):snprintf(t, sizeof(t), "bpl %+d", (s8)op1); break;
case (0x0b):snprintf(t, sizeof(t), "bmi %+d", (s8)op1); break;
case (0x0c):snprintf(t, sizeof(t), "bcc %+d", (s8)op1); break;
case (0x0d):snprintf(t, sizeof(t), "bcs %+d", (s8)op1); break;
case (0x0e):snprintf(t, sizeof(t), "bvc %+d", (s8)op1); break;
case (0x0f):snprintf(t, sizeof(t), "bvs %+d", (s8)op1); break;
case16(0x10):snprintf(t, sizeof(t), "to r%u", op0 & 15); break;
case16(0x20):snprintf(t, sizeof(t), "with r%u", op0 & 15); break;
case12(0x30):snprintf(t, sizeof(t), "stw (r%u)", op0 & 15); break;
case (0x3c):snprintf(t, sizeof(t), "loop"); break;
case (0x3d):snprintf(t, sizeof(t), "alt1"); break;
case (0x3e):snprintf(t, sizeof(t), "alt2"); break;
case (0x3f):snprintf(t, sizeof(t), "alt3"); break;
case12(0x40):snprintf(t, sizeof(t), "ldw (r%u)", op0 & 15); break;
case (0x4c):snprintf(t, sizeof(t), "plot"); break;
case (0x4d):snprintf(t, sizeof(t), "swap"); break;
case (0x4e):snprintf(t, sizeof(t), "color"); break;
case (0x4f):snprintf(t, sizeof(t), "not"); break;
case16(0x50):snprintf(t, sizeof(t), "add #%u", op0 & 15); break;
case16(0x60):snprintf(t, sizeof(t), "sub #%u", op0 & 15); break;
case (0x70):snprintf(t, sizeof(t), "merge"); break;
case15(0x71):snprintf(t, sizeof(t), "and #%u", op0 & 15); break;
case16(0x80):snprintf(t, sizeof(t), "mult #%u", op0 & 15); break;
case (0x90):snprintf(t, sizeof(t), "sbk"); break;
case4 (0x91):snprintf(t, sizeof(t), "link #%u", op0 & 15); break;
case (0x95):snprintf(t, sizeof(t), "sex"); break;
case (0x96):snprintf(t, sizeof(t), "asr"); break;
case (0x97):snprintf(t, sizeof(t), "ror"); break;
case6 (0x98):snprintf(t, sizeof(t), "jmp r%u", op0 & 15); break;
case (0x9e):snprintf(t, sizeof(t), "lob"); break;
case (0x9f):snprintf(t, sizeof(t), "fmult"); break;
case16(0xa0):snprintf(t, sizeof(t), "sms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
case16(0xb0):snprintf(t, sizeof(t), "from r%u", op0 & 15); break;
case (0xc0):snprintf(t, sizeof(t), "hib"); break;
case15(0xc1):snprintf(t, sizeof(t), "or #%u", op0 & 15); break;
case15(0xd0):snprintf(t, sizeof(t), "inc r%u", op0 & 15); break;
case (0xdf):snprintf(t, sizeof(t), "ramb"); break;
case15(0xe0):snprintf(t, sizeof(t), "dec r%u", op0 & 15); break;
case (0xef):snprintf(t, sizeof(t), "getbl"); break;
case16(0xf0):snprintf(t, sizeof(t), "sm r%u", op0 & 15); break;
}
strcat(output, t);
}
@@ -208,56 +208,56 @@ auto GSU::disassembleALT2(char* output) -> void {
auto GSU::disassembleALT3(char* output) -> void {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (s8)op1); break;
case (0x06): sprintf(t, "blt %+d", (s8)op1); break;
case (0x07): sprintf(t, "bge %+d", (s8)op1); break;
case (0x08): sprintf(t, "bne %+d", (s8)op1); break;
case (0x09): sprintf(t, "beq %+d", (s8)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (s8)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (s8)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (s8)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (s8)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (s8)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (s8)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "rpix"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "cmode"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "adc #%u", op0 & 15); break;
case16(0x60): sprintf(t, "cmp r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "bic #%u", op0 & 15); break;
case16(0x80): sprintf(t, "umult #%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "div2"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "lmult"); break;
case16(0xa0): sprintf(t, "lms r%u", op0 & 15); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "xor #%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "romb"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbs"); break;
case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break;
case (0x00):snprintf(t, sizeof(t), "stop"); break;
case (0x01):snprintf(t, sizeof(t), "nop"); break;
case (0x02):snprintf(t, sizeof(t), "cache"); break;
case (0x03):snprintf(t, sizeof(t), "lsr"); break;
case (0x04):snprintf(t, sizeof(t), "rol"); break;
case (0x05):snprintf(t, sizeof(t), "bra %+d", (s8)op1); break;
case (0x06):snprintf(t, sizeof(t), "blt %+d", (s8)op1); break;
case (0x07):snprintf(t, sizeof(t), "bge %+d", (s8)op1); break;
case (0x08):snprintf(t, sizeof(t), "bne %+d", (s8)op1); break;
case (0x09):snprintf(t, sizeof(t), "beq %+d", (s8)op1); break;
case (0x0a):snprintf(t, sizeof(t), "bpl %+d", (s8)op1); break;
case (0x0b):snprintf(t, sizeof(t), "bmi %+d", (s8)op1); break;
case (0x0c):snprintf(t, sizeof(t), "bcc %+d", (s8)op1); break;
case (0x0d):snprintf(t, sizeof(t), "bcs %+d", (s8)op1); break;
case (0x0e):snprintf(t, sizeof(t), "bvc %+d", (s8)op1); break;
case (0x0f):snprintf(t, sizeof(t), "bvs %+d", (s8)op1); break;
case16(0x10):snprintf(t, sizeof(t), "to r%u", op0 & 15); break;
case16(0x20):snprintf(t, sizeof(t), "with r%u", op0 & 15); break;
case12(0x30):snprintf(t, sizeof(t), "stb (r%u)", op0 & 15); break;
case (0x3c):snprintf(t, sizeof(t), "loop"); break;
case (0x3d):snprintf(t, sizeof(t), "alt1"); break;
case (0x3e):snprintf(t, sizeof(t), "alt2"); break;
case (0x3f):snprintf(t, sizeof(t), "alt3"); break;
case12(0x40):snprintf(t, sizeof(t), "ldb (r%u)", op0 & 15); break;
case (0x4c):snprintf(t, sizeof(t), "rpix"); break;
case (0x4d):snprintf(t, sizeof(t), "swap"); break;
case (0x4e):snprintf(t, sizeof(t), "cmode"); break;
case (0x4f):snprintf(t, sizeof(t), "not"); break;
case16(0x50):snprintf(t, sizeof(t), "adc #%u", op0 & 15); break;
case16(0x60):snprintf(t, sizeof(t), "cmp r%u", op0 & 15); break;
case (0x70):snprintf(t, sizeof(t), "merge"); break;
case15(0x71):snprintf(t, sizeof(t), "bic #%u", op0 & 15); break;
case16(0x80):snprintf(t, sizeof(t), "umult #%u", op0 & 15); break;
case (0x90):snprintf(t, sizeof(t), "sbk"); break;
case4 (0x91):snprintf(t, sizeof(t), "link #%u", op0 & 15); break;
case (0x95):snprintf(t, sizeof(t), "sex"); break;
case (0x96):snprintf(t, sizeof(t), "div2"); break;
case (0x97):snprintf(t, sizeof(t), "ror"); break;
case6 (0x98):snprintf(t, sizeof(t), "ljmp r%u", op0 & 15); break;
case (0x9e):snprintf(t, sizeof(t), "lob"); break;
case (0x9f):snprintf(t, sizeof(t), "lmult"); break;
case16(0xa0):snprintf(t, sizeof(t), "lms r%u", op0 & 15); break;
case16(0xb0):snprintf(t, sizeof(t), "from r%u", op0 & 15); break;
case (0xc0):snprintf(t, sizeof(t), "hib"); break;
case15(0xc1):snprintf(t, sizeof(t), "xor #%u", op0 & 15); break;
case15(0xd0):snprintf(t, sizeof(t), "inc r%u", op0 & 15); break;
case (0xdf):snprintf(t, sizeof(t), "romb"); break;
case15(0xe0):snprintf(t, sizeof(t), "dec r%u", op0 & 15); break;
case (0xef):snprintf(t, sizeof(t), "getbs"); break;
case16(0xf0):snprintf(t, sizeof(t), "lm r%u", op0 & 15); break;
}
strcat(output, t);
}
+2 -2
View File
@@ -75,8 +75,8 @@ struct GSU {
auto serialize(serializer&) -> void;
//disassembler.cpp
noinline auto disassembleInstruction() -> string;
noinline auto disassembleContext() -> string;
NALL_NOINLINE auto disassembleInstruction() -> string;
NALL_NOINLINE auto disassembleContext() -> string;
auto disassembleOpcode(char* output) -> void;
auto disassembleALT0(char* output) -> void;
+2 -2
View File
@@ -111,8 +111,8 @@ struct HG51B {
auto writeRegister(n7 address, n24 data) -> void;
//disassembler.cpp
noinline auto disassembleInstruction(maybe<n15> pb = {}, maybe<n8> pc = {}) -> string;
noinline auto disassembleContext() -> string;
NALL_NOINLINE auto disassembleInstruction(maybe<n15> pb = {}, maybe<n8> pc = {}) -> string;
NALL_NOINLINE auto disassembleContext() -> string;
protected:
struct Registers {
+2 -2
View File
@@ -124,8 +124,8 @@ struct I8080 {
auto serialize(serializer&) -> void;
//disassembler.cpp
noinline auto disassembleInstruction(maybe<n16> pc = {}) -> string;
noinline auto disassembleContext() -> string;
NALL_NOINLINE auto disassembleInstruction(maybe<n16> pc = {}) -> string;
NALL_NOINLINE auto disassembleContext() -> string;
auto disassemble(n16 pc, n8 prefix, n8 code) -> string;
@@ -338,28 +338,27 @@ template<u32 Size> auto M68000::instructionBTST(EffectiveAddress with) -> void {
}
auto M68000::instructionCHK(DataRegister compare, EffectiveAddress maximum) -> void {
auto source = read<Word>(maximum);
auto target = read<Word>(compare);
auto result = (n64)target - source;
r.c = sign<Word>(result >> 1) < 0;
r.v = sign<Word>((target ^ source) & (target ^ result)) < 0;
r.z = clip<Word>(result) == 0;
r.n = sign<Word>(result) < 0;
r.n ^= r.v;
prefetch();
auto source = read<Word>(compare);
auto target = read<Word>(maximum);
CMP<Word>(source, target);
idle(2);
bool bound = r.n || r.v;
CMP<Word>(0, source);
idle(2);
if(!r.n && !r.z) {
if(bound) {
prefetched();
return exception(Exception::BoundsCheck, Vector::BoundsCheck);
}
r.z = clip<Word>(target) == 0;
r.n = sign<Word>(target) < 0;
idle(2);
if(r.n) {
idle(2);
prefetched();
return exception(Exception::BoundsCheck, Vector::BoundsCheck);
}
idle(6);
prefetch();
}
template<u32 Size> auto M68000::instructionCLR(EffectiveAddress with) -> void {
@@ -43,7 +43,6 @@ auto M68000::power() -> void {
auto M68000::supervisor() -> bool {
if(r.s) return true;
r.pc -= 4;
exception(Exception::Unprivileged, Vector::Unprivileged);
return false;
}
+2 -2
View File
@@ -156,8 +156,8 @@ struct MOS6502 {
auto serialize(serializer&) -> void;
//disassembler.cpp
noinline auto disassembleInstruction(maybe<n16> pc = {}) -> string;
noinline auto disassembleContext() -> string;
NALL_NOINLINE auto disassembleInstruction(maybe<n16> pc = {}) -> string;
NALL_NOINLINE auto disassembleContext() -> string;
struct PR {
bool c; //carry
@@ -513,19 +513,19 @@ auto SH2::MOVI(u32 i, u32 n) -> void {
}
//MOV.W @(disp,PC),Rn
noinline auto SH2::MOVWI(u32 d, u32 n) -> void {
NALL_NOINLINE auto SH2::MOVWI(u32 d, u32 n) -> void {
u32 pc = inDelaySlot() ? PPC - 2 : PC;
R[n] = (s16)readWord(pc + d * 2);
}
//MOV.L @(disp,PC),Rn
noinline auto SH2::MOVLI(u32 d, u32 n) -> void {
NALL_NOINLINE auto SH2::MOVLI(u32 d, u32 n) -> void {
u32 pc = inDelaySlot() ? PPC - 2 : PC;
R[n] = readLong((pc & ~3) + d * 4);
}
//MOVA @(disp,PC),R0
noinline auto SH2::MOVA(u32 d) -> void {
NALL_NOINLINE auto SH2::MOVA(u32 d) -> void {
u32 pc = inDelaySlot() ? PPC - 2 : PC;
R[0] = (pc & ~3) + d * 4;
}
+1 -1
View File
@@ -131,7 +131,7 @@ auto SH2::Recompiler::emit(u32 address) -> Block* {
u16 instruction = instructions[index++];
if(callInstructionPrologue) {
mov32(reg(1), imm(instruction));
call(&SH2::instructionPrologue);
call(&SH2::instructionPrologueTrampoline);
}
auto branch = emitInstruction(instruction);
inDelaySlot = branch == Branch::Slot;
+2 -2
View File
@@ -65,8 +65,8 @@ auto SH2::power(bool reset) -> void {
if constexpr(Accuracy::Recompiler) {
if(!reset) {
auto buffer = ares::Memory::FixedAllocator::get().tryAcquire(64_MiB);
recompiler.allocator.resize(64_MiB, bump_allocator::executable, buffer);
auto buffer = ares::Memory::FixedAllocator::get().tryAcquire(32_MiB);
recompiler.allocator.resize(32_MiB, bump_allocator::executable, buffer);
}
recompiler.reset();
}
+7 -2
View File
@@ -249,6 +249,10 @@ struct SH2 {
s32 cyclesUntilRecompilerExit = 0;
s32 recompilerStepCycles = 0;
auto instructionPrologueTrampoline(u16 instruction) -> void {
return instructionPrologue(instruction); //virtual function call
}
struct Recompiler : recompiler::generic {
SH2& self;
Recompiler(SH2& self) : self(self), generic(allocator) {}
@@ -279,7 +283,8 @@ struct SH2 {
auto reset() -> void {
generation = 0;
blocks.reset();
for(u32 index : range(1 << 24)) pools[index] = nullptr;
pools.reallocate(1 << 24);
pools.fill();
}
auto invalidateCached() -> void {
@@ -307,7 +312,7 @@ struct SH2 {
bump_allocator allocator;
hashset<BlockHashPair> blocks;
u16 instructions[1 << 7];
Pool* pools[1 << 24];
vector<Pool*> pools;
} recompiler{*this};
#include "sh7604/sh7604.hpp"
@@ -105,8 +105,6 @@ auto SH2::Cache::purge() -> void {
}
auto SH2::Cache::power() -> void {
purge(4 * 256);
for(n6 n : range(64)) {
if(n.bit(5) == 1 && n.bit(4) == 1 && n.bit(3) == 1) { lruSelect[n] = 0; continue; }
if(n.bit(5) == 0 && n.bit(2) == 1 && n.bit(1) == 1) { lruSelect[n] = 1; continue; }
@@ -216,7 +216,7 @@
//watchdog timer
struct WDT {
//timer.cpp
auto run() -> void;
auto run(int cycles) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
@@ -282,7 +282,7 @@
maybe<SH2&> self;
//timer.cpp
auto run() -> void;
auto run(int cycles) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
+36 -34
View File
@@ -1,43 +1,45 @@
auto SH2::FRT::run() -> void {
auto SH2::FRT::run(int cycles) -> void {
static constexpr u32 frequencies[4] = {8, 32, 128, 1};
auto frequency = frequencies[tcr.cks];
if(++counter >= frequencies[tcr.cks]) {
counter -= frequencies[tcr.cks];
if(++frc == 0) {
ftcsr.ovf = 1;
if(tier.ovie) {
pendingOutputIRQ = 1;
}
}
if(frc == ocra) {
ftcsr.ocfa = 1;
if(tier.ociae) {
pendingOutputIRQ = 1;
}
if(ftcsr.cclra) {
frc = 0;
}
}
if(frc == ocrb) {
ftcsr.ocfb = 1;
if(tier.ocibe) {
pendingOutputIRQ = 1;
}
}
}
counter += cycles;
auto increments = counter / frequency;
counter -= increments * frequency;
if (!increments) return;
auto prevFrc = frc;
frc += increments;
ftcsr.ovf |= (frc < prevFrc);
ftcsr.ocfa |= (u32(ocra - 1 - prevFrc) < increments);
ftcsr.ocfb |= (u32(ocrb - 1 - prevFrc) < increments);
pendingOutputIRQ |= (tier.ovie & ftcsr.ovf) |
(tier.ociae & ftcsr.ocfa) |
(tier.ocibe & ftcsr.ocfb);
if (ftcsr.cclra && ftcsr.ocfa) frc = 0;
}
auto SH2::WDT::run() -> void {
auto SH2::WDT::run(int cycles) -> void {
static constexpr u32 frequencies[8] = {2, 64, 128, 256, 512, 1024, 4096, 8192};
if(!wtcsr.tme) return;
if(wtcsr.wtit) return; // Watchdog mode currently unsupported
if(!wtcsr.tme || wtcsr.wtit) return; //watchdog mode (wtit) currently unsupported
if(++counter >= frequencies[wtcsr.cks]) {
counter -= frequencies[wtcsr.cks];
auto frequency = frequencies[wtcsr.cks];
if(++wtcnt == 0) {
wtcsr.ovf = 1;
pendingIRQ = 1;
}
counter += cycles;
auto increments = counter / frequency;
counter %= frequency;
if(!increments) return;
auto prevWtcnt = wtcnt;
wtcnt += increments;
if (wtcnt < prevWtcnt) {
wtcsr.ovf = 1;
pendingIRQ = 1;
}
}
+2 -2
View File
@@ -29,8 +29,8 @@ struct SM83 {
//disassembler.cpp
virtual auto readDebugger(n16 address) -> n8 { return 0; }
noinline auto disassembleInstruction(maybe<n16> pc = {}) -> string;
noinline auto disassembleContext() -> string;
NALL_NOINLINE auto disassembleInstruction(maybe<n16> pc = {}) -> string;
NALL_NOINLINE auto disassembleContext() -> string;
//memory.cpp
auto operand() -> n8;
+3 -3
View File
@@ -117,9 +117,9 @@ struct SPC700 {
auto serialize(serializer&) -> void;
//disassembler.cpp
noinline auto disassembleInstruction(n16 address, n1 p) -> string;
noinline auto disassembleInstruction() -> string;
noinline auto disassembleContext() -> string;
NALL_NOINLINE auto disassembleInstruction(n16 address, n1 p) -> string;
NALL_NOINLINE auto disassembleInstruction() -> string;
NALL_NOINLINE auto disassembleContext() -> string;
struct Flags {
bool c; //carry
@@ -1,4 +1,4 @@
noinline auto TLCS900H::disassembleInstruction() -> string {
NALL_NOINLINE auto TLCS900H::disassembleInstruction() -> string {
string output;
auto pc = load(PC);
@@ -636,7 +636,7 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
return pad(output, -48);
}
noinline auto TLCS900H::disassembleContext() -> string {
NALL_NOINLINE auto TLCS900H::disassembleContext() -> string {
string output;
output.append("XWA:", hex(r.xwa[RFP].l.l0, 8L), " ");
output.append("XBC:", hex(r.xbc[RFP].l.l0, 8L), " ");
@@ -25,8 +25,8 @@ struct uPD96050 {
auto writeDP(n12 address, n8 data) -> void;
//disassembler.cpp
noinline auto disassembleInstruction(maybe<n14> ip = {}) -> string;
noinline auto disassembleContext() -> string;
NALL_NOINLINE auto disassembleInstruction(maybe<n14> ip = {}) -> string;
NALL_NOINLINE auto disassembleContext() -> string;
enum class Revision : u32 { uPD7725, uPD96050 } revision;
n24 programROM[16384];
@@ -235,9 +235,9 @@ struct WDC65816 {
auto serialize(serializer&) -> void;
//disassembler.cpp
noinline auto disassembleInstruction(n24 address, bool e, bool m, bool x) -> string;
noinline auto disassembleInstruction() -> string;
noinline auto disassembleContext(maybe<bool> e = {}) -> string;
NALL_NOINLINE auto disassembleInstruction(n24 address, bool e, bool m, bool x) -> string;
NALL_NOINLINE auto disassembleInstruction() -> string;
NALL_NOINLINE auto disassembleContext(maybe<bool> e = {}) -> string;
struct f8 {
bool c = 0; //carry
+2 -2
View File
@@ -211,8 +211,8 @@ struct Z80 {
auto serialize(serializer&) -> void;
//disassembler.cpp
noinline auto disassembleInstruction(maybe<n16> pc = {}) -> string;
noinline auto disassembleContext() -> string;
NALL_NOINLINE auto disassembleInstruction(maybe<n16> pc = {}) -> string;
NALL_NOINLINE auto disassembleContext() -> string;
auto disassemble(n16 pc, n8 prefix, n8 code) -> string;
auto disassembleCB(n16 pc, n8 prefix, n8 code) -> string;
+97
View File
@@ -0,0 +1,97 @@
ares_components(z80 tms9918 sn76489)
ares_add_sources(
CORE #
cv
UNITY #
cv.cpp
PRIMARY #
cpu/cpu.cpp
vdp/vdp.cpp
psg/psg.cpp
system/system.cpp
cartridge/cartridge.cpp
controller/controller.cpp
)
ares_add_sources(
CORE #
cv
INCLUDED #
cv.hpp
CMakeLists.txt
)
ares_add_sources(
CORE #
cv
INCLUDED #
cartridge/cartridge.hpp
cartridge/serialization.cpp
cartridge/slot.cpp
cartridge/slot.hpp
)
ares_add_sources(
CORE #
cv
INCLUDED #
cartridge/board/board.cpp
cartridge/board/board.hpp
cartridge/board/coleco.cpp
cartridge/board/megacart.cpp
cartridge/board/xin1.cpp
)
ares_add_sources(
CORE #
cv
INCLUDED #
controller/controller.hpp
controller/port.cpp
controller/port.hpp
)
ares_add_sources(
CORE #
cv
INCLUDED #
controller/gamepad/gamepad.cpp
controller/gamepad/gamepad.hpp
)
ares_add_sources(
CORE #
cv
INCLUDED #
cpu/cpu.hpp
cpu/debugger.cpp
cpu/memory.cpp
cpu/serialization.cpp
)
ares_add_sources(
CORE #
cv
INCLUDED #
psg/psg.hpp
psg/serialization.cpp
)
ares_add_sources(
CORE #
cv
INCLUDED #
system/controls.cpp
system/serialization.cpp
system/system.hpp
)
ares_add_sources(
CORE #
cv
INCLUDED #
vdp/color.cpp
vdp/serialization.cpp
vdp/vdp.hpp
)
+8
View File
@@ -0,0 +1,8 @@
//started: 2019-02-19
#include <cv/cpu/cpu.cpp>
#include <cv/vdp/vdp.cpp>
#include <cv/psg/psg.cpp>
#include <cv/system/system.cpp>
#include <cv/cartridge/cartridge.cpp>
#include <cv/controller/controller.cpp>
+4 -4
View File
@@ -44,10 +44,10 @@ auto VDP::frame() -> void {
screen->setSize(284, 243);
screen->setViewport(0, 0, 284, 243);
} else {
int x = 16;
int y = 16;
int width = 284 - 32;
int height = 243 - 32;
int x = 13;
int y = 27;
int width = 284 - 28;
int height = 243 - 51;
screen->setSize(width, height);
screen->setViewport(x, y, width, height);
+220
View File
@@ -0,0 +1,220 @@
ares_components(
mos6502
ym2149
ym2413
m24c
sst39sf0x0
)
target_link_libraries(ares PRIVATE ymfm)
ares_add_sources(
CORE #
fc
UNITY #
fc.cpp
PRIMARY #
system/system.cpp
controller/controller.cpp
expansion/expansion.cpp
cartridge/cartridge.cpp
cpu/cpu.cpp
apu/apu.cpp
ppu/ppu.cpp
fds/fds.cpp
)
ares_add_sources(CORE fc INCLUDED fc.hpp CMakeLists.txt)
ares_add_sources(
CORE #
fc
INCLUDED #
apu/apu.hpp
apu/dmc.cpp
apu/envelope.cpp
apu/framecounter.cpp
apu/length.cpp
apu/noise.cpp
apu/pulse.cpp
apu/serialization.cpp
apu/sweep.cpp
apu/triangle.cpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
cartridge/cartridge.hpp
cartridge/serialization.cpp
cartridge/slot.cpp
cartridge/slot.hpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
cartridge/board/action53.cpp
cartridge/board/ave-nina-001.cpp
cartridge/board/ave-nina-06.cpp
cartridge/board/bandai-74161.cpp
cartridge/board/bandai-fcg.cpp
cartridge/board/bandai-karaoke.cpp
cartridge/board/bandai-lz93d50.cpp
cartridge/board/bandai-oeka.cpp
cartridge/board/board.cpp
cartridge/board/board.hpp
cartridge/board/camerica-bf909x.cpp
cartridge/board/colordreams-74x377.cpp
cartridge/board/gtrom.cpp
cartridge/board/hvc-axrom.cpp
cartridge/board/hvc-bnrom.cpp
cartridge/board/hvc-cnrom.cpp
cartridge/board/hvc-exrom.cpp
cartridge/board/hvc-fmr.cpp
cartridge/board/hvc-fxrom.cpp
cartridge/board/hvc-gxrom.cpp
cartridge/board/hvc-hkrom.cpp
cartridge/board/hvc-nrom.cpp
cartridge/board/hvc-pxrom.cpp
cartridge/board/hvc-sxrom.cpp
cartridge/board/hvc-txrom.cpp
cartridge/board/hvc-uxrom.cpp
cartridge/board/inl-nsf.cpp
cartridge/board/irem-g101.cpp
cartridge/board/irem-h3001.cpp
cartridge/board/irem-lrog017.cpp
cartridge/board/irem-tam-s1.cpp
cartridge/board/jaleco-jf05.cpp
cartridge/board/jaleco-jf11.cpp
cartridge/board/jaleco-jf16.cpp
cartridge/board/jaleco-jf17.cpp
cartridge/board/jaleco-jf23.cpp
cartridge/board/konami-vrc1.cpp
cartridge/board/konami-vrc2.cpp
cartridge/board/konami-vrc3.cpp
cartridge/board/konami-vrc4.cpp
cartridge/board/konami-vrc5.cpp
cartridge/board/konami-vrc6.cpp
cartridge/board/konami-vrc7.cpp
cartridge/board/magicfloor.cpp
cartridge/board/mlt-action52.cpp
cartridge/board/namco-118.cpp
cartridge/board/namco-163.cpp
cartridge/board/namco-340.cpp
cartridge/board/sunsoft-1.cpp
cartridge/board/sunsoft-2.cpp
cartridge/board/sunsoft-3.cpp
cartridge/board/sunsoft-4.cpp
cartridge/board/sunsoft-5b.cpp
cartridge/board/taito-tc0190.cpp
cartridge/board/taito-tc0690.cpp
cartridge/board/taito-x1-005.cpp
cartridge/board/taito-x1-017.cpp
cartridge/board/tengen-80003x.cpp
cartridge/board/unl-bmc.cpp
cartridge/board/unl-sachen-74ls374n.cpp
cartridge/board/unl-sachen-sa0037.cpp
cartridge/board/unl-txc.cpp
cartridge/board/unrom-512.cpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
cartridge/board/ic/jv001.hpp
cartridge/board/ic/txc05-00002-010.hpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
controller/controller.hpp
controller/port.cpp
controller/port.hpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
controller/gamepad/gamepad.cpp
controller/gamepad/gamepad.hpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
cpu/cpu.hpp
cpu/debugger.cpp
cpu/memory.cpp
cpu/serialization.cpp
cpu/timing.cpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
expansion/expansion.hpp
expansion/port.cpp
expansion/port.hpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
expansion/epsm/epsm.cpp
expansion/epsm/epsm.hpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
expansion/family-keyboard/family-keyboard.cpp
expansion/family-keyboard/family-keyboard.hpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
fds/audio.cpp
fds/audio.hpp
fds/drive.cpp
fds/drive.hpp
fds/fds.hpp
fds/serialization.cpp
fds/timer.cpp
fds/timer.hpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
ppu/color.cpp
ppu/debugger.cpp
ppu/memory.cpp
ppu/ppu.hpp
ppu/render.cpp
ppu/scroll.cpp
ppu/serialization.cpp
ppu/sprite.cpp
)
ares_add_sources(
CORE #
fc
INCLUDED #
system/controls.cpp
system/serialization.cpp
system/system.hpp
)
+1
View File
@@ -1,4 +1,5 @@
#include <fc/fc.hpp>
#include <ares/resource/resource.hpp>
namespace ares::Famicom {
+2 -1
View File
@@ -9,7 +9,8 @@ auto CPU::read(n16 address) -> n8 {
}
auto CPU::write(n16 address, n8 data) -> void {
writeBus(address, io.openBus = data);
writeBus(address, data);
io.openBus = data;
step(rate());
}
+10
View File
@@ -0,0 +1,10 @@
//started: 2011-09-05
#include <fc/system/system.cpp>
#include <fc/controller/controller.cpp>
#include <fc/expansion/expansion.cpp>
#include <fc/cartridge/cartridge.cpp>
#include <fc/cpu/cpu.cpp>
#include <fc/apu/apu.cpp>
#include <fc/ppu/ppu.cpp>
#include <fc/fds/fds.cpp>
+6 -3
View File
@@ -81,6 +81,12 @@ auto FDS::connect() -> void {
auto FDS::disconnect() -> void {
if(!node) return;
save();
pak.reset();
node.reset();
}
auto FDS::save() -> void {
if(disk1.sideA)
if(auto fp = pak->write("disk1.sideA")) {
disk1.sideA.save(fp);
@@ -100,9 +106,6 @@ auto FDS::disconnect() -> void {
if(auto fp = pak->write("disk2.sideB")) {
disk2.sideB.save(fp);
}
pak.reset();
node.reset();
}
auto FDS::change(string value) -> void {
+1
View File
@@ -34,6 +34,7 @@ struct FDS {
auto change(string value) -> void;
auto change() -> void;
auto save() -> void;
auto poll() -> void;
auto main() -> void;
auto power() -> void;
+9 -1
View File
@@ -81,7 +81,10 @@ auto PPU::writeIO(n16 address, n8 data) -> void {
//PPUCTRL
case 0:
scroll.nametable = data.bit(0,1);
scroll.nametable = data.bit(0,1);
if (io.lx == 257 && rendering())
var.nametableX = cpu.io.openBus.bit(0);
io.vramIncrement = data.bit(2) ? 32 : 1;
io.spriteAddress = data.bit(3) ? 0x1000 : 0x0000;
io.bgAddress = data.bit(4) ? 0x1000 : 0x0000;
@@ -141,6 +144,9 @@ auto PPU::writeIO(n16 address, n8 data) -> void {
if(scroll.latch++ == 0) {
scroll.fineX = data.bit(0,2);
scroll.tileX = data.bit(3,7);
if (io.lx == 257 && rendering())
var.tileX = cpu.io.openBus.bit(3,7);
} else {
scroll.fineY = data.bit(0,2);
scroll.tileY = data.bit(3,7);
@@ -151,6 +157,8 @@ auto PPU::writeIO(n16 address, n8 data) -> void {
case 6:
if(scroll.latch++ == 0) {
scroll.addressHi = data.bit(0,5);
if (io.lx == 257 && rendering())
var.nametable = cpu.io.openBus.bit(2,3);
} else {
scroll.addressLo = data.bit(0,7);
scroll.transferDelay = 3;
+7 -4
View File
@@ -97,11 +97,14 @@ auto PPU::frame() -> void {
screen->setViewport(0, 0, 283, displayHeight());
} else {
int x = 16;
int y = 8;
int width = 283 - 33;
int height = displayHeight() - 16;
int y = 0;
int width = 283 - 27;
int height = displayHeight() - 2;
if(Region::PAL()) height -= 48;
if(Region::PAL()) {
x += 2;
height -= 46;
}
screen->setSize(width, height);
screen->setViewport(x, y, width, height);
+2 -2
View File
@@ -25,8 +25,8 @@ auto PPU::renderPixel() -> void {
u32 objectPalette = 0;
bool objectPriority = 0;
//PAL systems blank the topmost scanline and the first and last 2px of active display
if(Region::PAL()) if(io.ly == 0 || x < 2 || x > 254) return;
//PAL systems technically blank the topmost scanline and a 2px column on each side of active display.
if(Region::PAL()) if(io.ly == 0 || x < 2 || x > 253) return;
palette |= latch.tiledataLo & mask ? 1 : 0;
palette |= latch.tiledataHi & mask ? 2 : 0;
+1
View File
@@ -85,6 +85,7 @@ auto System::load(Node::System& root, string name) -> bool {
auto System::save() -> void {
if(!node) return;
cartridge.save();
if(fds.present) fds.save();
}
auto System::unload() -> void {
+97
View File
@@ -0,0 +1,97 @@
ares_components(sm83 m93lcx6)
ares_add_sources(
CORE #
gb
UNITY #
gb.cpp
PRIMARY #
system/system.cpp
cartridge/cartridge.cpp
bus/bus.cpp
cpu/cpu.cpp
ppu/ppu.cpp
apu/apu.cpp
)
ares_add_sources(
CORE #
gb
INCLUDED #
gb.hpp
CMakeLists.txt
)
ares_add_sources(
CORE #
gb
INCLUDED #
apu/apu.hpp
apu/io.cpp
apu/noise.cpp
apu/sequencer.cpp
apu/serialization.cpp
apu/square1.cpp
apu/square2.cpp
apu/wave.cpp
)
ares_add_sources(
CORE #
gb
INCLUDED #
bus/bus.hpp
)
ares_add_sources(
CORE #
gb
INCLUDED #
cartridge/cartridge.hpp
cartridge/memory.cpp
cartridge/serialization.cpp
cartridge/slot.cpp
cartridge/slot.hpp
)
ares_add_sources(
CORE #
gb
INCLUDED #
cartridge/board/board.cpp
cartridge/board/board.hpp
cartridge/board/huc1.cpp
cartridge/board/huc3.cpp
cartridge/board/linear.cpp
cartridge/board/mbc1.cpp
cartridge/board/mbc1m.cpp
cartridge/board/mbc2.cpp
cartridge/board/mbc3.cpp
cartridge/board/mbc5.cpp
cartridge/board/mbc6.cpp
cartridge/board/mbc7.cpp
cartridge/board/mmm01.cpp
cartridge/board/none.cpp
cartridge/board/tama.cpp
)
ares_add_sources(
CORE #
gb
INCLUDED #
cpu/cpu.hpp
cpu/debugger.cpp
cpu/io.cpp
cpu/memory.cpp
cpu/serialization.cpp
cpu/timing.cpp
)
ares_add_sources(
CORE #
gb
INCLUDED #
system/controls.cpp
system/serialization.cpp
system/system.hpp
)
+8
View File
@@ -0,0 +1,8 @@
//started: 2010-12-27
#include <gb/system/system.cpp>
#include <gb/cartridge/cartridge.cpp>
#include <gb/bus/bus.cpp>
#include <gb/cpu/cpu.cpp>
#include <gb/ppu/ppu.cpp>
#include <gb/apu/apu.cpp>
+122
View File
@@ -0,0 +1,122 @@
ares_components(arm7tdmi)
ares_add_sources(
CORE #
gba
UNITY #
gba.cpp
PRIMARY #
memory/memory.cpp
system/system.cpp
cartridge/cartridge.cpp
player/player.cpp
cpu/cpu.cpp
display/display.cpp
ppu/ppu.cpp
apu/apu.cpp
)
ares_add_sources(
CORE #
gba
INCLUDED #
gba.hpp
CMakeLists.txt
)
ares_add_sources(
CORE #
gba
INCLUDED #
apu/apu.hpp
apu/fifo.cpp
apu/io.cpp
apu/noise.cpp
apu/sequencer.cpp
apu/serialization.cpp
apu/square.cpp
apu/square1.cpp
apu/square2.cpp
apu/wave.cpp
)
ares_add_sources(
CORE #
gba
INCLUDED #
cartridge/cartridge.hpp
cartridge/eeprom.cpp
cartridge/flash.cpp
cartridge/memory.hpp
cartridge/mrom.cpp
cartridge/serialization.cpp
cartridge/slot.cpp
cartridge/slot.hpp
cartridge/sram.cpp
)
ares_add_sources(
CORE #
gba
INCLUDED #
cpu/bus.cpp
cpu/cpu.hpp
cpu/debugger.cpp
cpu/dma.cpp
cpu/io.cpp
cpu/keypad.cpp
cpu/memory.cpp
cpu/prefetch.cpp
cpu/serialization.cpp
cpu/timer.cpp
)
ares_add_sources(
CORE #
gba
INCLUDED #
display/display.hpp
display/io.cpp
display/serialization.cpp
)
ares_add_sources(
CORE #
gba
INCLUDED #
memory/memory.hpp
)
ares_add_sources(
CORE #
gba
INCLUDED #
player/player.hpp
player/serialization.cpp
)
ares_add_sources(
CORE #
gba
INCLUDED #
ppu/background.cpp
ppu/color.cpp
ppu/dac.cpp
ppu/debugger.cpp
ppu/io.cpp
ppu/memory.cpp
ppu/object.cpp
ppu/ppu.hpp
ppu/serialization.cpp
ppu/window.cpp
)
ares_add_sources(
CORE #
gba
INCLUDED #
system/bios.cpp
system/controls.cpp
system/serialization.cpp
system/system.hpp
)
+2
View File
@@ -7,6 +7,7 @@ ares.objects += ares-gba-player
ares.objects += ares-gba-cpu
ares.objects += ares-gba-ppu
ares.objects += ares-gba-apu
ares.objects += ares-gba-display
$(object.path)/ares-gba-memory.o: $(ares.path)/gba/memory/memory.cpp
$(object.path)/ares-gba-system.o: $(ares.path)/gba/system/system.cpp
@@ -15,3 +16,4 @@ $(object.path)/ares-gba-player.o: $(ares.path)/gba/player/player.cpp
$(object.path)/ares-gba-cpu.o: $(ares.path)/gba/cpu/cpu.cpp
$(object.path)/ares-gba-ppu.o: $(ares.path)/gba/ppu/ppu.cpp
$(object.path)/ares-gba-apu.o: $(ares.path)/gba/apu/apu.cpp
$(object.path)/ares-gba-display.o: $(ares.path)/gba/display/display.cpp
+5 -1
View File
@@ -1,4 +1,6 @@
auto APU::readIO(n32 address) -> n8 {
cpu.synchronize(apu);
switch(address) {
//NR10
@@ -140,10 +142,12 @@ auto APU::readIO(n32 address) -> n8 {
}
return cpu.pipeline.fetch.instruction.byte(address & 1);
return cpu.openBus.get(Byte, address);
}
auto APU::writeIO(n32 address, n8 data) -> void {
cpu.synchronize(apu);
switch(address) {
//NR10
+143 -44
View File
@@ -1,42 +1,76 @@
auto CPU::sleep() -> void {
dmaRun();
ARM7TDMI::irq = irq.synchronizer;
prefetchStep(1);
}
template <bool UseDebugger>
inline auto CPU::getBus(u32 mode, n32 address) -> n32 {
u32 clocks = _wait(mode, address);
u32 word = pipeline.fetch.instruction;
u32 word;
if(address >= 0x1000'0000) {
if constexpr(!UseDebugger) prefetchStep(clocks);
} else if(address & 0x0800'0000) {
if(memory.biosSwap && address < 0x0400'0000) address ^= 0x0200'0000;
switch(address >> 24) {
case 0x00: case 0x01:
if constexpr(!UseDebugger) prefetchStep(1);
word = bios.read(mode, address);
break;
case 0x02:
if constexpr(!UseDebugger) prefetchStep(waitEWRAM(mode));
word = readEWRAM(mode, address);
break;
case 0x03:
if constexpr(!UseDebugger) prefetchStep(1);
word = readIWRAM(mode, address);
break;
case 0x04:
if constexpr(!UseDebugger) prefetchStep(1);
if((address & 0xffff'fc00) == 0x0400'0000) word = bus.io[address & 0x3ff]->readIO(mode, address);
else if((address & 0xff00'ffff) == 0x0400'0800) word = ((IO*)this)->readIO(mode, 0x0400'0800 | (address & 3));
else return openBus.get(mode, address);
break;
//timings for VRAM and PRAM are handled in memory.cpp
case 0x05: word = readPRAM<UseDebugger>(mode, address); break;
case 0x06: word = readVRAM<UseDebugger>(mode, address); break;
case 0x07:
if constexpr(!UseDebugger) prefetchStep(1);
word = ppu.readOAM(mode, address);
break;
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
if(mode & Prefetch && wait.prefetch) {
dmaRun();
prefetchSync(address);
word = prefetchRead(mode);
prefetchStep(1);
word = prefetchRead();
if(mode & Word) word |= prefetchRead() << 16;
} else {
if constexpr(!UseDebugger) prefetchReset();
if constexpr(!UseDebugger) step(clocks);
if constexpr(!UseDebugger) step(waitCartridge(mode, address));
word = cartridge.read(mode, address);
}
} else {
if(memory.biosSwap && address < 0x0400'0000) address ^= 0x0200'0000;
if constexpr(!UseDebugger) prefetchStep(clocks);
if(auto result = platform->cheat(address)) return *result;
if(address < 0x0200'0000) word = bios.read(mode, address);
else if(address < 0x0300'0000) word = readEWRAM(mode, address);
else if(address < 0x0400'0000) word = readIWRAM(mode, address);
else if(address >= 0x0700'0000) word = ppu.readOAM(mode, address);
else if(address >= 0x0600'0000) word = ppu.readVRAM(mode, address);
else if(address >= 0x0500'0000) word = ppu.readPRAM(mode, address);
else if((address & 0xffff'fc00) == 0x0400'0000) word = bus.io[address & 0x3ff]->readIO(mode, address);
else if((address & 0xff00'ffff) == 0x0400'0800) word = ((IO*)this)->readIO(mode, 0x0400'0800 | (address & 3));
break;
default:
if constexpr(!UseDebugger) prefetchStep(1);
return openBus.get(mode, address);
}
openBus.set(mode, address, word);
if(auto result = platform->cheat(address)) return *result;
return word;
}
auto CPU::get(u32 mode, n32 address) -> n32 {
dmaRun();
ARM7TDMI::irq = irq.synchronizer;
return getBus<false>(mode, address);
}
@@ -45,36 +79,73 @@ auto CPU::getDebugger(u32 mode, n32 address) -> n32 {
}
auto CPU::set(u32 mode, n32 address, n32 word) -> void {
u32 clocks = _wait(mode, address);
dmaRun();
ARM7TDMI::irq = irq.synchronizer;
if(address >= 0x1000'0000) {
prefetchStep(clocks);
} else if(address & 0x0800'0000) {
prefetchReset();
step(clocks);
cartridge.write(mode, address, word);
} else {
if(memory.biosSwap && address < 0x0400'0000) address ^= 0x0200'0000;
prefetchStep(clocks);
if(address < 0x0200'0000) bios.write(mode, address, word);
else if(address < 0x0300'0000) writeEWRAM(mode, address, word);
else if(address < 0x0400'0000) writeIWRAM(mode, address, word);
else if(address >= 0x0700'0000) ppu.writeOAM(mode, address, word);
else if(address >= 0x0600'0000) ppu.writeVRAM(mode, address, word);
else if(address >= 0x0500'0000) ppu.writePRAM(mode, address, word);
else if((address & 0xffff'fc00) == 0x0400'0000) bus.io[address & 0x3ff]->writeIO(mode, address, word);
if(memory.biosSwap && address < 0x0400'0000) address ^= 0x0200'0000;
switch(address >> 24) {
case 0x00: case 0x01:
prefetchStep(1);
bios.write(mode, address, word);
break;
case 0x02:
prefetchStep(waitEWRAM(mode));
writeEWRAM(mode, address, word);
break;
case 0x03:
prefetchStep(1);
writeIWRAM(mode, address, word);
break;
case 0x04:
prefetchStep(1);
if((address & 0xffff'fc00) == 0x0400'0000) bus.io[address & 0x3ff]->writeIO(mode, address, word);
else if((address & 0xff00'ffff) == 0x0400'0800) ((IO*)this)->writeIO(mode, 0x0400'0800 | (address & 3), word);
break;
//timings for VRAM and PRAM are handled in memory.cpp
case 0x05: writePRAM(mode, address, word); break;
case 0x06: writeVRAM(mode, address, word); break;
case 0x07:
prefetchStep(1);
synchronize(ppu);
ppu.writeOAM(mode, address, word);
break;
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
prefetchReset();
step(waitCartridge(mode, address));
cartridge.write(mode, address, word);
break;
default:
prefetchStep(1);
break;
}
openBus.set(mode, address, word);
}
auto CPU::_wait(u32 mode, n32 address) -> u32 {
if(address >= 0x1000'0000) return 1; //unmapped
if(address < 0x0200'0000) return 1;
if(address < 0x0300'0000) return (16 - memory.ewramWait) * (mode & Word ? 2 : 1);
if(address < 0x0500'0000) return 1;
if(address < 0x0700'0000) return mode & Word ? 2 : 1;
if(address < 0x0800'0000) return 1;
auto CPU::lock() -> void {
dmaRun();
context.busLocked = true;
}
auto CPU::unlock() -> void {
context.busLocked = false;
}
auto CPU::waitEWRAM(u32 mode) -> u32 {
return (16 - memory.ewramWait) * (mode & Word ? 2 : 1);
}
auto CPU::waitCartridge(u32 mode, n32 address) -> u32 {
static u32 timings[] = {5, 4, 3, 9};
u32 n = timings[wait.nwait[address >> 25 & 3]];
u32 s = wait.swait[address >> 25 & 3];
@@ -93,3 +164,31 @@ auto CPU::_wait(u32 mode, n32 address) -> u32 {
if(mode & Word) clocks += s; //16-bit bus requires two transfers for words
return clocks;
}
auto CPU::OpenBus::get(u32 mode, n32 address) -> n32 {
if(mode & Word) address &= ~3;
if(mode & Half) address &= ~1;
return data >> (8 * (address & 3));
}
auto CPU::OpenBus::set(u32 mode, n32 address, n32 word) -> void {
if(address >> 24 == 0x3) {
//open bus from IWRAM only overwrites part of the last IWRAM value accessed
if(mode & Word) {
iwramData = word;
} else if(mode & Half) {
if(address & 2) {
iwramData.bit(16,31) = (n16)word;
} else {
iwramData.bit( 0,15) = (n16)word;
}
} else if(mode & Byte) {
iwramData.byte(address & 3) = (n8)word;
}
data = iwramData;
} else {
if(mode & Byte) word = (word & 0xff) * 0x01010101;
if(mode & Half) word = (word & 0xffff) * 0x00010001;
data = word;
}
}
+31 -18
View File
@@ -30,20 +30,24 @@ auto CPU::unload() -> void {
}
auto CPU::main() -> void {
ARM7TDMI::irq = irq.ime && (irq.enable & irq.flag);
if(stopped()) {
if(!(irq.enable & irq.flag & Interrupt::Keypad)) {
Thread::step(16);
if(!keypad.conditionMet) {
stepIRQ();
Thread::step(1);
Thread::synchronize();
return;
}
Thread::step(2);
Thread::synchronize();
context.stopped = false;
}
if(halted()) {
if(!(irq.enable & irq.flag)) {
return step(16);
dmaRun();
if(!(irq.enable[0] & irq.flag[0])) {
return step(4);
}
step(2);
context.halted = false;
}
@@ -52,7 +56,7 @@ auto CPU::main() -> void {
}
auto CPU::dmaRun() -> void {
if(!context.dmaActive && !context.prefetchActive) {
if(!context.dmaActive && !context.busLocked) {
context.dmaActive = true;
while(dma[0].run() | dma[1].run() | dma[2].run() | dma[3].run());
if(context.dmaRan) {
@@ -64,17 +68,27 @@ auto CPU::dmaRun() -> void {
}
}
auto CPU::setInterruptFlag(u32 source) -> void {
irq.flag[1] |= source;
}
inline auto CPU::stepIRQ() -> void {
irq.synchronizer = irq.ime[0] && (irq.enable[0] & irq.flag[0]);
irq.enable[0] = irq.enable[1];
irq.flag[0] = irq.flag[1];
irq.ime[0] = irq.ime[1];
}
auto CPU::step(u32 clocks) -> void {
if(!clocks) return;
dmaRun();
dma[0].waiting = max(0, dma[0].waiting - (s32)clocks);
dma[1].waiting = max(0, dma[1].waiting - (s32)clocks);
dma[2].waiting = max(0, dma[2].waiting - (s32)clocks);
dma[3].waiting = max(0, dma[3].waiting - (s32)clocks);
for(auto _ : range(clocks)) {
stepIRQ();
timer[0].run();
timer[1].run();
timer[2].run();
@@ -93,17 +107,16 @@ auto CPU::step(u32 clocks) -> void {
context.clock++;
}
#if defined(PROFILE_PERFORMANCE)
//10-20% speedup by only synchronizing other components every 16 clock cycles
Thread::step(clocks);
Thread::synchronize(display, player);
//occasionally synchronize with PPU and APU in case CPU has not recently interacted with them
static u32 counter = 0;
counter += clocks;
if(counter < 16) return;
clocks = counter;
counter = 0;
#endif
Thread::step(clocks);
Thread::synchronize();
if(counter >= 1024) {
Thread::synchronize(ppu, apu);
counter = 0;
}
}
auto CPU::power() -> void {
+30 -7
View File
@@ -47,6 +47,8 @@ struct CPU : ARM7TDMI, Thread, IO {
auto main() -> void;
auto dmaRun() -> void;
auto setInterruptFlag(u32 source) -> void;
auto stepIRQ() -> void;
auto step(u32 clocks) -> void override;
auto power() -> void;
@@ -54,7 +56,7 @@ struct CPU : ARM7TDMI, Thread, IO {
auto prefetchSync(n32 address) -> void;
auto prefetchStep(u32 clocks) -> void;
auto prefetchReset() -> void;
auto prefetchRead(u32 mode) -> n32;
auto prefetchRead() -> n16;
//bus.cpp
auto sleep() -> void override;
@@ -62,7 +64,10 @@ struct CPU : ARM7TDMI, Thread, IO {
auto get(u32 mode, n32 address) -> n32 override;
auto getDebugger(u32 mode, n32 address) -> n32 override;
auto set(u32 mode, n32 address, n32 word) -> void override;
auto _wait(u32 mode, n32 address) -> u32;
auto lock() -> void override;
auto unlock() -> void override;
auto waitEWRAM(u32 mode) -> u32;
auto waitCartridge(u32 mode, n32 address) -> u32;
//io.cpp
auto readIO(n32 address) -> n8 override;
@@ -74,6 +79,12 @@ struct CPU : ARM7TDMI, Thread, IO {
auto readEWRAM(u32 mode, n32 address) -> n32;
auto writeEWRAM(u32 mode, n32 address, n32 word) -> void;
template<bool UseDebugger> auto readPRAM(u32 mode, n32 address) -> n32;
auto writePRAM(u32 mode, n32 address, n32 word) -> void;
template<bool UseDebugger> auto readVRAM(u32 mode, n32 address) -> n32;
auto writeVRAM(u32 mode, n32 address, n32 word) -> void;
//dma.cpp
auto dmaVblank() -> void;
auto dmaHblank() -> void;
@@ -158,7 +169,8 @@ struct CPU : ARM7TDMI, Thread, IO {
n1 transferEnableReceive;
n1 transferEnableSend;
n1 startBit;
n1 transferLength;
n4 uartFlags;
n2 mode;
n1 irqEnable;
n16 data[4];
@@ -172,6 +184,8 @@ struct CPU : ARM7TDMI, Thread, IO {
n1 enable;
n1 condition;
n1 flag[10];
n1 conditionMet;
} keypad;
struct Joybus {
@@ -200,9 +214,10 @@ struct CPU : ARM7TDMI, Thread, IO {
} joybus;
struct IRQ {
n1 ime;
n16 enable;
n16 flag;
n1 ime[2];
n1 synchronizer;
n16 enable[2];
n16 flag[2];
} irq;
struct Wait {
@@ -221,6 +236,13 @@ struct CPU : ARM7TDMI, Thread, IO {
n4 unknown2;
} memory;
struct OpenBus {
auto get(u32 mode, n32 address) -> n32;
auto set(u32 mode, n32 address, n32 word) -> void;
n32 data;
n32 iwramData;
} openBus;
struct {
auto empty() const { return addr == load; }
auto full() const { return load - addr == 16; }
@@ -230,6 +252,7 @@ struct CPU : ARM7TDMI, Thread, IO {
n32 addr; //read location of slot buffer
n32 load; //write location of slot buffer
i32 wait = 1; //number of clocks before next slot load
n1 stopped = 1;
} prefetch;
struct Context {
@@ -240,8 +263,8 @@ struct CPU : ARM7TDMI, Thread, IO {
n1 dmaRan;
n1 dmaRomAccess;
n1 dmaActive;
n1 prefetchActive;
n1 timerLatched;
n1 busLocked;
} context;
};
+2 -2
View File
@@ -2,8 +2,8 @@ inline auto CPU::DMA::run() -> bool {
if(!active || waiting) return false;
transfer();
if(irq) cpu.irq.flag |= CPU::Interrupt::DMA0 << id;
if(drq && id == 3) cpu.irq.flag |= CPU::Interrupt::Cartridge;
if(irq) cpu.setInterruptFlag(CPU::Interrupt::DMA0 << id);
if(drq && id == 3) cpu.setInterruptFlag(CPU::Interrupt::Cartridge);
return true;
}
+21 -19
View File
@@ -55,8 +55,9 @@ auto CPU::readIO(n32 address) -> n8 {
| serial.startBit << 7
);
case 0x0400'0129: return (
serial.transferLength << 4
| serial.irqEnable << 6
serial.uartFlags << 0
| serial.mode << 4
| serial.irqEnable << 6
);
//SIOMLT_SEND (SIODATA8)
@@ -183,12 +184,12 @@ auto CPU::readIO(n32 address) -> n8 {
case 0x0400'015b: return 0;
//IE
case 0x0400'0200: return irq.enable.byte(0);
case 0x0400'0201: return irq.enable.byte(1);
case 0x0400'0200: return irq.enable[0].byte(0);
case 0x0400'0201: return irq.enable[0].byte(1);
//IF
case 0x0400'0202: return irq.flag.byte(0);
case 0x0400'0203: return irq.flag.byte(1);
case 0x0400'0202: return irq.flag[0].byte(0);
case 0x0400'0203: return irq.flag[0].byte(1);
//WAITCNT
case 0x0400'0204: return (
@@ -211,7 +212,7 @@ auto CPU::readIO(n32 address) -> n8 {
case 0x0400'0207: return 0;
//IME
case 0x0400'0208: return irq.ime;
case 0x0400'0208: return irq.ime[0];
case 0x0400'0209: return 0;
//zero
@@ -243,7 +244,7 @@ auto CPU::readIO(n32 address) -> n8 {
}
return cpu.pipeline.fetch.instruction.byte(address & 1);
return cpu.openBus.get(Byte, address);
}
auto CPU::writeIO(n32 address, n8 data) -> void {
@@ -339,8 +340,9 @@ auto CPU::writeIO(n32 address, n8 data) -> void {
serial.startBit = data.bit(7);
return;
case 0x0400'0129:
serial.transferLength = data.bit(4);
serial.irqEnable = data.bit(6);
serial.uartFlags = data.bit(0,3);
serial.mode = data.bit(4,5);
serial.irqEnable = data.bit(6);
return;
//SIOMLT_SEND (SIODATA8)
@@ -383,10 +385,10 @@ auto CPU::writeIO(n32 address, n8 data) -> void {
//JOYCNT
case 0x0400'0140:
joybus.resetSignal = data.bit(0);
joybus.receiveComplete = data.bit(1);
joybus.sendComplete = data.bit(2);
joybus.resetIRQEnable = data.bit(6);
joybus.resetSignal &= ~data.bit(0);
joybus.receiveComplete &= ~data.bit(1);
joybus.sendComplete &= ~data.bit(2);
joybus.resetIRQEnable = data.bit(6);
return;
case 0x0400'0141: return;
case 0x0400'0142: return;
@@ -415,12 +417,12 @@ auto CPU::writeIO(n32 address, n8 data) -> void {
case 0x0400'0159: return;
//IE
case 0x0400'0200: irq.enable.byte(0) = data; return;
case 0x0400'0201: irq.enable.byte(1) = data; return;
case 0x0400'0200: irq.enable[1].byte(0) = data; return;
case 0x0400'0201: irq.enable[1].byte(1) = data; return;
//IF
case 0x0400'0202: irq.flag.byte(0) = irq.flag.byte(0) & ~data; return;
case 0x0400'0203: irq.flag.byte(1) = irq.flag.byte(1) & ~data; return;
case 0x0400'0202: irq.flag[1].byte(0) = irq.flag[1].byte(0) & ~data; return;
case 0x0400'0203: irq.flag[1].byte(1) = irq.flag[1].byte(1) & ~data; return;
//WAITCNT
case 0x0400'0204:
@@ -440,7 +442,7 @@ auto CPU::writeIO(n32 address, n8 data) -> void {
return;
//IME
case 0x0400'0208: irq.ime = data.bit(0); return;
case 0x0400'0208: irq.ime[1] = data.bit(0); return;
case 0x0400'0209: return;
//POSTFLG, HALTCNT
+6 -8
View File
@@ -1,7 +1,4 @@
auto CPU::Keypad::run() -> void {
if(!enable) return;
system.controls.poll();
const bool lookup[] = {
system.controls.a->value(),
system.controls.b->value(),
@@ -15,12 +12,13 @@ auto CPU::Keypad::run() -> void {
system.controls.l->value(),
};
bool test = condition; //0 = OR, 1 = AND
conditionMet = condition; //0 = OR, 1 = AND
for(u32 index : range(10)) {
if(!flag[index]) continue;
bool input = lookup[index];
if(condition == 0) test |= input;
if(condition == 1) test &= input;
n1 input = lookup[index];
if(condition == 0) conditionMet |= input;
if(condition == 1) conditionMet &= input;
}
if(test) cpu.irq.flag |= CPU::Interrupt::Keypad;
if(conditionMet && enable) cpu.setInterruptFlag(CPU::Interrupt::Keypad);
}
+58
View File
@@ -47,3 +47,61 @@ auto CPU::writeEWRAM(u32 mode, n32 address, n32 word) -> void {
ewram[address & 0x3ffff] = word;
}
template <bool UseDebugger>
auto CPU::readPRAM(u32 mode, n32 address) -> n32 {
if(mode & Word) return readPRAM<UseDebugger>(Half, address & ~2) << 0 | readPRAM<UseDebugger>(Half, address | 2) << 16;
//stall until PPU is no longer accessing PRAM (minimum 1 cycle)
do {
prefetchStep(1);
synchronize(ppu);
} while(ppu.pramContention());
return ppu.readPRAM(mode, address);
}
auto CPU::writePRAM(u32 mode, n32 address, n32 word) -> void {
if(mode & Word) {
writePRAM(Half, address & ~2, word >> 0);
writePRAM(Half, address | 2, word >> 16);
return;
}
//stall until PPU is no longer accessing PRAM (minimum 1 cycle)
do {
prefetchStep(1);
synchronize(ppu);
} while(ppu.pramContention());
ppu.writePRAM(mode, address, word);
}
template <bool UseDebugger>
auto CPU::readVRAM(u32 mode, n32 address) -> n32 {
if(mode & Word) return readVRAM<UseDebugger>(Half, address & ~2) << 0 | readVRAM<UseDebugger>(Half, address | 2) << 16;
//stall until PPU is no longer accessing VRAM (minimum 1 cycle)
do {
prefetchStep(1);
synchronize(ppu);
} while(ppu.vramContention(address));
return ppu.readVRAM(mode, address);
}
auto CPU::writeVRAM(u32 mode, n32 address, n32 word) -> void {
if(mode & Word) {
writeVRAM(Half, address & ~2, word >> 0);
writeVRAM(Half, address | 2, word >> 16);
return;
}
//stall until PPU is no longer accessing VRAM (minimum 1 cycle)
do {
prefetchStep(1);
synchronize(ppu);
} while(ppu.vramContention(address));
ppu.writeVRAM(mode, address, word);
}
+16 -23
View File
@@ -3,52 +3,45 @@ auto CPU::prefetchSync(n32 address) -> void {
if(prefetch.wait == 1) step(1);
prefetch.stopped = false;
prefetch.addr = address;
prefetch.load = address;
prefetch.wait = _wait(Half | Nonsequential, prefetch.load);
prefetch.wait = waitCartridge(Half | Nonsequential, prefetch.load);
}
auto CPU::prefetchStep(u32 clocks) -> void {
step(clocks);
if(!wait.prefetch || context.dmaRomAccess || (prefetch.addr == 0)) return;
if(!wait.prefetch || context.dmaRomAccess || prefetch.stopped) return;
while(!prefetch.full() && clocks--) {
if(--prefetch.wait) continue;
prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load);
prefetch.load += 2;
prefetch.wait = _wait(Half | Sequential, prefetch.load);
prefetch.wait = waitCartridge(Half | Sequential, prefetch.load);
}
if(prefetch.full()) prefetch.stopped = true;
}
auto CPU::prefetchReset() -> void {
if(prefetch.wait == 1) step(1);
prefetch.stopped = true;
prefetch.wait = 0;
prefetch.addr = 0;
prefetch.load = 0;
prefetch.wait = 0;
}
auto CPU::prefetchRead(u32 mode) -> n32 {
//run prefetcher for 1 cycle or until buffer contains an instruction, blocking DMA
context.prefetchActive = 1;
if(prefetch.empty() && (mode & Word)) {
prefetchStep(prefetch.wait + _wait(Half | Sequential, prefetch.load + 2));
} else if(prefetch.empty() && (mode & Half)) {
prefetchStep(prefetch.wait);
} else if((prefetch.size() == 1) && (mode & Word)) {
prefetchStep(prefetch.wait);
} else {
prefetchStep(1);
}
context.prefetchActive = 0;
auto CPU::prefetchRead() -> n16 {
if(prefetch.empty()) prefetchStep(prefetch.wait);
if(prefetch.full()) prefetch.wait = _wait(Half | Sequential, prefetch.load);
n32 word = prefetch.slot[prefetch.addr >> 1 & 7];
n16 word = prefetch.slot[prefetch.addr >> 1 & 7];
prefetch.addr += 2;
if(mode & Word) {
word |= prefetch.slot[prefetch.addr >> 1 & 7] << 16;
prefetch.addr += 2;
if(prefetch.stopped && prefetch.empty()) {
prefetch.stopped = false;
prefetch.wait = waitCartridge(Half | Nonsequential, prefetch.load);
}
return word;
}
+12 -5
View File
@@ -52,7 +52,8 @@ auto CPU::serialize(serializer& s) -> void {
s(serial.transferEnableReceive);
s(serial.transferEnableSend);
s(serial.startBit);
s(serial.transferLength);
s(serial.uartFlags);
s(serial.mode);
s(serial.irqEnable);
for(auto& value : serial.data) s(value);
s(serial.data8);
@@ -60,6 +61,7 @@ auto CPU::serialize(serializer& s) -> void {
s(keypad.enable);
s(keypad.condition);
for(auto& flag : keypad.flag) s(flag);
s(keypad.conditionMet);
s(joybus.sc);
s(joybus.sd);
@@ -81,9 +83,10 @@ auto CPU::serialize(serializer& s) -> void {
s(joybus.sendFlag);
s(joybus.generalFlag);
s(irq.ime);
s(irq.enable);
s(irq.flag);
for(auto& flag : irq.ime) s(flag);
s(irq.synchronizer);
for(auto& flag : irq.enable) s(flag);
for(auto& flag : irq.flag) s(flag);
for(auto& flag : wait.nwait) s(flag);
for(auto& flag : wait.swait) s(flag);
@@ -97,10 +100,14 @@ auto CPU::serialize(serializer& s) -> void {
s(memory.ewramWait);
s(memory.unknown2);
s(openBus.data);
s(openBus.iwramData);
s(prefetch.slot);
s(prefetch.addr);
s(prefetch.load);
s(prefetch.wait);
s(prefetch.stopped);
s(context.clock);
s(context.halted);
@@ -109,6 +116,6 @@ auto CPU::serialize(serializer& s) -> void {
s(context.dmaRan);
s(context.dmaRomAccess);
s(context.dmaActive);
s(context.prefetchActive);
s(context.timerLatched);
s(context.busLocked);
}
+1 -1
View File
@@ -43,7 +43,7 @@ auto CPU::Timer::step() -> void {
if(++period == 0) {
period = reload;
if(irq) cpu.irq.flag |= CPU::Interrupt::Timer0 << id;
if(irq) cpu.setInterruptFlag(CPU::Interrupt::Timer0 << id);
if(apu.fifo[0].timer == id) cpu.runFIFO(0);
if(apu.fifo[1].timer == id) cpu.runFIFO(1);
+89
View File
@@ -0,0 +1,89 @@
#include <gba/gba.hpp>
//The only PPU state the CPU needs on every cycle is raised IRQs and DMAs,
//which occur independently of the render process.
//Display exists to put these events on a separate thread,
//so the CPU and PPU can run out-of-order.
//hdraw: 1006 cycles
//hblank: 226 cycles
//scanline: 1232 cycles
//vdraw: 160 scanlines (197120 cycles)
//vblank: 68 scanlines ( 83776 cycles)
//frame: 228 scanlines (280896 cycles)
namespace ares::GameBoyAdvance {
Display display;
#include "io.cpp"
#include "serialization.cpp"
auto Display::load(Node::Object parent) -> void {
node = parent->append<Node::Object>("Display");
}
auto Display::unload() -> void {
node.reset();
}
auto Display::step(u32 clocks) -> void {
Thread::step(clocks);
Thread::synchronize(cpu);
}
auto Display::main() -> void {
cpu.keypad.run();
io.vblank = io.vcounter >= 160 && io.vcounter <= 226;
step(1);
io.vcoincidence = io.vcounter == io.vcompare;
if(io.vcounter == 160) {
if(io.irqvblank) cpu.setInterruptFlag(CPU::Interrupt::VBlank);
}
step(1);
if(io.irqvcoincidence) {
if(io.vcoincidence) cpu.setInterruptFlag(CPU::Interrupt::VCoincidence);
}
if(io.vcounter == 160) {
cpu.dmaVblank();
}
step(3);
if(io.vcounter == 162) {
if(videoCapture) cpu.dma[3].enable = 0;
videoCapture = !videoCapture && cpu.dma[3].timingMode == 3 && cpu.dma[3].enable;
}
if(io.vcounter >= 2 && io.vcounter < 162 && videoCapture) cpu.dmaHDMA();
step(1002);
io.hblank = 1;
step(1);
if(io.irqhblank) cpu.setInterruptFlag(CPU::Interrupt::HBlank);
step(1);
if(io.vcounter < 160) cpu.dmaHblank();
step(223);
io.hblank = 0;
if(++io.vcounter == 228) io.vcounter = 0;
}
auto Display::power() -> void {
Thread::create(system.frequency(), {&Display::main, this});
for(u32 n = 0x004; n <= 0x007; n++) bus.io[n] = this;
io = {};
}
}
+34
View File
@@ -0,0 +1,34 @@
struct Display : Thread, IO {
Node::Object node;
auto load(Node::Object) -> void;
auto unload() -> void;
auto step(u32 clocks) -> void;
auto main() -> void;
auto power() -> void;
//io.cpp
auto readIO(n32 address) -> n8;
auto writeIO(n32 address, n8 byte) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
struct IO {
n1 vblank;
n1 hblank;
n1 vcoincidence;
n1 irqvblank;
n1 irqhblank;
n1 irqvcoincidence;
n8 vcompare;
n16 vcounter;
} io;
n1 videoCapture = 0;
};
extern Display display;
+40
View File
@@ -0,0 +1,40 @@
auto Display::readIO(n32 address) -> n8 {
switch(address) {
//DISPSTAT
case 0x0400'0004: return (
io.vblank << 0
| io.hblank << 1
| io.vcoincidence << 2
| io.irqvblank << 3
| io.irqhblank << 4
| io.irqvcoincidence << 5
);
case 0x0400'0005: return (
io.vcompare
);
//VCOUNT
case 0x0400'0006: return io.vcounter.byte(0);
case 0x0400'0007: return io.vcounter.byte(1);
}
return cpu.openBus.get(Byte, address);
}
auto Display::writeIO(n32 address, n8 data) -> void {
switch(address) {
//DISPSTAT
case 0x0400'0004:
io.irqvblank = data.bit(3);
io.irqhblank = data.bit(4);
io.irqvcoincidence = data.bit(5);
return;
case 0x0400'0005:
io.vcompare = data;
return;
}
}
+14
View File
@@ -0,0 +1,14 @@
auto Display::serialize(serializer& s) -> void {
Thread::serialize(s);
s(io.vblank);
s(io.hblank);
s(io.vcoincidence);
s(io.irqvblank);
s(io.irqhblank);
s(io.irqvcoincidence);
s(io.vcompare);
s(io.vcounter);
s(videoCapture);
}
+10
View File
@@ -0,0 +1,10 @@
//started: 2012-03-19
#include <gba/memory/memory.cpp>
#include <gba/system/system.cpp>
#include <gba/cartridge/cartridge.cpp>
#include <gba/player/player.cpp>
#include <gba/cpu/cpu.cpp>
#include <gba/display/display.cpp>
#include <gba/ppu/ppu.cpp>
#include <gba/apu/apu.cpp>
+2
View File
@@ -9,6 +9,7 @@ namespace ares::GameBoyAdvance {
#include <ares/inline.hpp>
auto enumerate() -> vector<string>;
auto load(Node::System& node, string name) -> bool;
auto option(string name, string value) -> bool;
enum : u32 { //mode flags for bus read, write:
Nonsequential = 1, //N cycle
@@ -34,4 +35,5 @@ namespace ares::GameBoyAdvance {
#include <gba/cpu/cpu.hpp>
#include <gba/ppu/ppu.hpp>
#include <gba/apu/apu.hpp>
#include <gba/display/display.hpp>
}
+1 -1
View File
@@ -42,7 +42,7 @@ auto IO::writeIO(u32 mode, n32 address, n32 word) -> void {
struct UnmappedIO : IO {
auto readIO(n32 address) -> n8 override {
return cpu.pipeline.fetch.instruction.byte(address & 1);
return cpu.openBus.get(Byte, address);
}
auto writeIO(n32 address, n8 byte) -> void override {
+2 -2
View File
@@ -63,7 +63,7 @@ auto Player::frame() -> void {
&& !cpu.serial.transferEnableReceive
&& cpu.serial.transferEnableSend
&& cpu.serial.startBit
&& cpu.serial.transferLength
&& cpu.serial.mode == 0x1
&& cpu.serial.irqEnable
) {
status.packet = (status.packet + 1) % 17;
@@ -86,7 +86,7 @@ auto Player::frame() -> void {
case 15: status.send = 0x30000003; break;
case 16: status.send = 0x30000003; break;
}
cpu.irq.flag |= CPU::Interrupt::Serial;
cpu.setInterruptFlag(CPU::Interrupt::Serial);
}
}
+98 -60
View File
@@ -4,17 +4,26 @@ n1 PPU::Background::IO::frame;
n5 PPU::Background::IO::mosaicWidth;
n5 PPU::Background::IO::mosaicHeight;
auto PPU::Background::setEnable(n1 status) -> void {
io.enable[3] = status;
for(auto& flag : io.enable) flag &= status;
}
auto PPU::Background::scanline(u32 y) -> void {
mosaicOffset = 0;
for(auto& pixel : output) pixel = {};
}
auto PPU::Background::outputPixel(u32 x, u32 y) -> void {
//horizontal mosaic
if(!io.mosaic || !mosaicOffset) {
mosaicOffset = 1 + io.mosaicWidth;
mosaic = output[x];
}
mosaicOffset--;
}
auto PPU::Background::run(u32 x, u32 y) -> void {
output = {};
if(ppu.blank() || !io.enable) {
mosaic = {};
return;
}
switch(id) {
case PPU::BG0:
if(io.mode <= 1) { linear(x, y); break; }
@@ -26,24 +35,50 @@ auto PPU::Background::run(u32 x, u32 y) -> void {
case PPU::BG2:
if(io.mode == 0) { linear(x, y); break; }
if(io.mode <= 2) { affine(x, y); break; }
if(io.mode <= 2) { affineFetchTileMap(x, y); affineFetchTileData(x, y); break; }
if(io.mode <= 5) { bitmap(x, y); break; }
break;
case PPU::BG3:
if(io.mode == 0) { linear(x, y); break; }
if(io.mode == 2) { affine(x, y); break; }
if(io.mode == 2) { affineFetchTileMap(x, y); affineFetchTileData(x, y); break; }
break;
}
}
//horizontal mosaic
if(!io.mosaic || ++mosaicOffset >= 1 + io.mosaicWidth) {
mosaicOffset = 0;
mosaic = output;
}
auto PPU::Background::linearFetchTileMap() -> void {
n6 tx = fx >> 3;
n6 ty = fy >> 3;
u32 offset = (ty & 31) << 5 | (tx & 31);
if(io.screenSize.bit(0) && (tx & 32)) offset += 32 << 5;
if(io.screenSize.bit(1) && (ty & 32)) offset += 32 << 5 + io.screenSize.bit(0);
offset = (io.screenBase << 11) + (offset << 1);
n16 tilemap = ppu.readVRAM_BG(Half, offset);
latch.character = tilemap.bit(0,9);
latch.hflip = tilemap.bit(10);
latch.vflip = tilemap.bit(11);
latch.palette = tilemap.bit(12,15);
}
auto PPU::Background::linearFetchTileData() -> void {
n3 px = fx;
n3 py = fy;
if(latch.hflip) px = ~px;
if(latch.vflip) py = ~py;
u32 tileOffset = ((latch.character << 5) + (py << 2)) << io.colorMode;
u32 pixelOffset = px >> (1 - io.colorMode);
u32 offset = (io.characterBase << 14) + tileOffset + pixelOffset;
latch.data = ppu.readVRAM_BG(Half, offset);
}
auto PPU::Background::linear(u32 x, u32 y) -> void {
if(x > 239) return;
if(ppu.blank() || !io.enable[0]) return;
if(x == 0) {
if(!io.mosaic || (y % (1 + io.mosaicHeight)) == 0) {
vmosaic = y;
@@ -55,45 +90,40 @@ auto PPU::Background::linear(u32 x, u32 y) -> void {
n3 px = fx;
n3 py = fy;
if(x == 0 || px == 0) {
n6 tx = fx >> 3;
n6 ty = fy >> 3;
u32 offset = (ty & 31) << 5 | (tx & 31);
if(io.screenSize.bit(0) && (tx & 32)) offset += 32 << 5;
if(io.screenSize.bit(1) && (ty & 32)) offset += 32 << 5 + io.screenSize.bit(0);
offset = (io.screenBase << 11) + (offset << 1);
n16 tilemap = ppu.readVRAM(Half, offset);
latch.character = tilemap.bit(0,9);
latch.hflip = tilemap.bit(10);
latch.vflip = tilemap.bit(11);
latch.palette = tilemap.bit(12,15);
if(x == 0 || px == 0) linearFetchTileMap();
if(x == 0) {
linearFetchTileData();
} else if(io.colorMode == 0 && (px & 3) == 0) {
linearFetchTileData();
} else if(io.colorMode == 1 && (px & 1) == 0) {
linearFetchTileData();
}
if(latch.hflip) px = ~px;
if(latch.vflip) py = ~py;
n16 color = latch.data;
if(io.colorMode == 0) {
u32 offset = (io.characterBase << 14) + (latch.character << 5) + (py << 2) + (px >> 1);
if(n4 color = ppu.readVRAM_BG(Byte, offset) >> (px & 1 ? 4 : 0)) {
output.enable = true;
output.priority = io.priority;
output.color = ppu.pram[latch.palette << 4 | color];
}
color >>= (px & 3) * 4;
color = (n4)color;
} else {
u32 offset = (io.characterBase << 14) + (latch.character << 6) + (py << 3) + (px);
if(n8 color = ppu.readVRAM_BG(Byte, offset)) {
output.enable = true;
output.priority = io.priority;
output.color = ppu.pram[color];
}
color >>= (px & 1) * 8;
color = (n8)color;
}
if(color) {
if(io.colorMode == 0) color |= latch.palette << 4;
output[x].enable = true;
output[x].priority = io.priority;
output[x].color = color;
}
fx++;
}
auto PPU::Background::affine(u32 x, u32 y) -> void {
auto PPU::Background::affineFetchTileMap(u32 x, u32 y) -> void {
if(x > 239) return;
if(ppu.blank() || !io.enable[0]) return;
if(x == 0) {
if(!io.mosaic || (y % (1 + io.mosaicHeight)) == 0) {
hmosaic = io.lx;
@@ -103,24 +133,29 @@ auto PPU::Background::affine(u32 x, u32 y) -> void {
fy = vmosaic;
}
u32 screenSize = 16 << io.screenSize;
u32 screenWrap = (1 << (io.affineWrap ? 7 + io.screenSize : 20)) - 1;
affine.screenSize = 16 << io.screenSize;
affine.screenWrap = (1 << (io.affineWrap ? 7 + io.screenSize : 20)) - 1;
u32 cx = (fx >> 8) & screenWrap;
u32 cy = (fy >> 8) & screenWrap;
affine.cx = (fx >> 8) & affine.screenWrap;
affine.cy = (fy >> 8) & affine.screenWrap;
u32 tx = cx >> 3;
u32 ty = cy >> 3;
affine.tx = affine.cx >> 3;
affine.ty = affine.cy >> 3;
n3 px = cx;
n3 py = cy;
affine.character = ppu.readVRAM_BG(Byte, (io.screenBase << 11) + affine.ty * affine.screenSize + affine.tx);
}
if(tx < screenSize && ty < screenSize) {
n8 character = ppu.readVRAM(Byte, (io.screenBase << 11) + ty * screenSize + tx);
if(n8 color = ppu.readVRAM_BG(Byte, (io.characterBase << 14) + (character << 6) + (py << 3) + px)) {
output.enable = true;
output.priority = io.priority;
output.color = ppu.pram[color];
auto PPU::Background::affineFetchTileData(u32 x, u32 y) -> void {
if(x > 239) return;
if(ppu.blank() || !io.enable[0]) return;
if(affine.tx < affine.screenSize && affine.ty < affine.screenSize) {
n3 px = affine.cx;
n3 py = affine.cy;
if(n8 color = ppu.readVRAM_BG(Byte, (io.characterBase << 14) + (affine.character << 6) + (py << 3) + px)) {
output[x].enable = true;
output[x].priority = io.priority;
output[x].color = color;
}
}
@@ -134,6 +169,9 @@ auto PPU::Background::affine(u32 x, u32 y) -> void {
}
auto PPU::Background::bitmap(u32 x, u32 y) -> void {
if(x > 239) return;
if(ppu.blank() || !io.enable[0]) return;
if(x == 0) {
if(!io.mosaic || (y % (1 + io.mosaicHeight)) == 0) {
hmosaic = io.lx;
@@ -158,10 +196,10 @@ auto PPU::Background::bitmap(u32 x, u32 y) -> void {
n15 color = ppu.readVRAM_BG(mode, baseAddress + (offset << depth));
if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque
if(depth == 0) color = ppu.pram[color];
output.enable = true;
output.priority = io.priority;
output.color = color;
if(depth) output[x].directColor = true;
output[x].enable = true;
output[x].priority = io.priority;
output[x].color = color;
}
}
@@ -179,7 +217,7 @@ auto PPU::Background::power(u32 id) -> void {
io = {};
latch = {};
output = {};
for(auto& pixel : output) pixel = {};
mosaic = {};
mosaicOffset = 0;
hmosaic = 0;
+49 -24
View File
@@ -1,5 +1,13 @@
auto PPU::DAC::run(u32 x, u32 y) -> n15 {
if(ppu.blank()) return 0x7fff;
auto PPU::DAC::scanline(u32 y) -> void {
line = ppu.screen->pixels().data() + y * 240;
}
auto PPU::DAC::upperLayer(u32 x, u32 y) -> void {
if(ppu.blank()) {
color = 0x7fff;
blending = false;
return;
}
//determine active window
n1 active[6] = {true, true, true, true, true, true}; //enable all layers if no windows are enabled
@@ -11,16 +19,15 @@ auto PPU::DAC::run(u32 x, u32 y) -> n15 {
}
//priority sorting: find topmost two pixels
Pixel layers[6] = {
ppu.objects.mosaic,
ppu.bg0.mosaic,
ppu.bg1.mosaic,
ppu.bg2.mosaic,
ppu.bg3.mosaic,
{true, 3, ppu.pram[0]},
};
layers[OBJ] = ppu.objects.mosaic;
layers[BG0] = ppu.bg0.mosaic;
layers[BG1] = ppu.bg1.mosaic;
layers[BG2] = ppu.bg2.mosaic;
layers[BG3] = ppu.bg3.mosaic;
layers[SFX] = {true, 3, 0};
u32 aboveLayer = 5, belowLayer = 5;
aboveLayer = 5;
belowLayer = 5;
for(s32 priority = 3; priority >= 0; priority--) {
for(s32 layer = 5; layer >= 0; layer--) {
if(layers[layer].enable && layers[layer].priority == priority && active[layer]) {
@@ -31,26 +38,44 @@ auto PPU::DAC::run(u32 x, u32 y) -> n15 {
}
auto above = layers[aboveLayer];
auto below = layers[belowLayer];
auto eva = min(16u, (u32)io.blendEVA);
auto evb = min(16u, (u32)io.blendEVB);
auto evy = min(16u, (u32)io.blendEVY);
n15 color = above.color;
color = pramLookup(above);
//color blending
if(active[SFX] || (above.translucent && io.blendBelow[belowLayer])) {
if(above.translucent && io.blendBelow[belowLayer]) {
color = blend(above.color, eva, below.color, evb);
} else if(io.blendMode == 1 && io.blendAbove[aboveLayer] && io.blendBelow[belowLayer]) {
color = blend(above.color, eva, below.color, evb);
if(above.translucent && io.blendBelow[belowLayer]) {
blending = true;
return;
}
if(active[SFX]) {
auto evy = min(16u, (u32)io.blendEVY);
if(io.blendMode == 1 && io.blendAbove[aboveLayer] && io.blendBelow[belowLayer]) {
blending = true;
return;
} else if(io.blendMode == 2 && io.blendAbove[aboveLayer]) {
color = blend(above.color, 16 - evy, 0x7fff, evy);
color = blend(color, 16 - evy, 0x7fff, evy);
} else if(io.blendMode == 3 && io.blendAbove[aboveLayer]) {
color = blend(above.color, 16 - evy, 0x0000, evy);
color = blend(color, 16 - evy, 0x0000, evy);
}
}
return color;
blending = false;
}
auto PPU::DAC::lowerLayer(u32 x, u32 y) -> void {
if(blending) {
auto below = layers[belowLayer];
auto eva = min(16u, (u32)io.blendEVA);
auto evb = min(16u, (u32)io.blendEVB);
color = blend(color, eva, pramLookup(below), evb);
}
line[x] = color;
}
inline auto PPU::DAC::pramLookup(Pixel& layer) -> n15 {
if(layer.directColor) return layer.color;
ppu.pramAccessed = true;
return ppu.pram[layer.color];
}
auto PPU::DAC::blend(n15 above, u32 eva, n15 below, u32 evb) -> n15 {
+21 -43
View File
@@ -1,4 +1,6 @@
auto PPU::readIO(n32 address) -> n8 {
cpu.synchronize(ppu);
switch(address) {
//DISPCNT
@@ -8,40 +10,23 @@ auto PPU::readIO(n32 address) -> n8 {
| Background::IO::frame << 4
| objects.io.hblank << 5
| objects.io.mapping << 6
| io.forceBlank << 7
| io.forceBlank[3] << 7
);
case 0x0400'0001: return (
bg0.io.enable << 0
| bg1.io.enable << 1
| bg2.io.enable << 2
| bg3.io.enable << 3
| objects.io.enable << 4
| window0.io.enable << 5
| window1.io.enable << 6
| window2.io.enable << 7
bg0.io.enable[3] << 0
| bg1.io.enable[3] << 1
| bg2.io.enable[3] << 2
| bg3.io.enable[3] << 3
| objects.io.enable[3] << 4
| window0.io.enable << 5
| window1.io.enable << 6
| window2.io.enable << 7
);
//GRSWP
case 0x0400'0002: return io.greenSwap;
case 0x0400'0003: return 0;
//DISPSTAT
case 0x0400'0004: return (
io.vblank << 0
| io.hblank << 1
| io.vcoincidence << 2
| io.irqvblank << 3
| io.irqhblank << 4
| io.irqvcoincidence << 5
);
case 0x0400'0005: return (
io.vcompare
);
//VCOUNT
case 0x0400'0006: return io.vcounter.byte(0);
case 0x0400'0007: return io.vcounter.byte(1);
//BG0CNT
case 0x0400'0008: return bg0.io.priority << 0 | bg0.io.characterBase << 2 | bg0.io.unused << 4 | bg0.io.mosaic << 6 | bg0.io.colorMode << 7;
case 0x0400'0009: return bg0.io.screenBase << 0 | bg0.io.affineWrap << 5 | bg0.io.screenSize << 6;
@@ -99,10 +84,12 @@ auto PPU::readIO(n32 address) -> n8 {
}
return cpu.pipeline.fetch.instruction.byte(address & 1);
return cpu.openBus.get(Byte, address);
}
auto PPU::writeIO(n32 address, n8 data) -> void {
cpu.synchronize(ppu);
switch(address) {
//DISPCNT
@@ -112,14 +99,15 @@ auto PPU::writeIO(n32 address, n8 data) -> void {
Background::IO::frame = data.bit(4);
objects.io.hblank = data.bit(5);
objects.io.mapping = data.bit(6);
io.forceBlank = data.bit(7);
io.forceBlank[3] = data.bit(7);
for(auto& flag : io.forceBlank) flag |= data.bit(7);
return;
case 0x0400'0001:
bg0.io.enable = data.bit(0);
bg1.io.enable = data.bit(1);
bg2.io.enable = data.bit(2);
bg3.io.enable = data.bit(3);
objects.io.enable = data.bit(4);
bg0.setEnable(data.bit(0));
bg1.setEnable(data.bit(1));
bg2.setEnable(data.bit(2));
bg3.setEnable(data.bit(3));
objects.setEnable(data.bit(4));
window0.io.enable = data.bit(5);
window1.io.enable = data.bit(6);
window2.io.enable = data.bit(7);
@@ -134,16 +122,6 @@ auto PPU::writeIO(n32 address, n8 data) -> void {
case 0x0400'0003:
return;
//DISPSTAT
case 0x0400'0004:
io.irqvblank = data.bit(3);
io.irqhblank = data.bit(4);
io.irqvcoincidence = data.bit(5);
return;
case 0x0400'0005:
io.vcompare = data;
return;
//BG0CNT
case 0x0400'0008:
bg0.io.priority = data.bit(0,1);
+31 -30
View File
@@ -1,20 +1,34 @@
auto PPU::readVRAM_BG(u32 mode, n32 address) -> n32 {
auto PPU::releaseBus() -> void {
pramAccessed = false;
vramAccessedBG = false;
}
auto PPU::pramContention() -> bool {
return pramAccessed;
}
auto PPU::vramContention(n32 address) -> bool {
address &= 0x1ffff;
if(Background::IO::mode < 3 && address >= 0x10000) return false;
else if(address >= 0x14000) return false;
return vramAccessedBG;
}
auto PPU::readVRAM_BG(u32 mode, n32 address) -> n16 {
if(Background::IO::mode < 3 && address >= 0x10000) return 0;
else if(address >= 0x14000) return 0;
vramAccessedBG = true;
return readVRAM(mode, address);
}
auto PPU::readVRAM(u32 mode, n32 address) -> n32 {
auto PPU::readVRAM(u32 mode, n32 address) -> n16 {
address &= 0x1ffff;
if(Background::IO::mode >= 3 && address < 0x1c000 && address >= 0x18000) return 0;
address &= (address & 0x10000) ? 0x17fff : 0x0ffff;
if(mode & Word) {
address &= ~3;
return vram[address + 0] << 0 | vram[address + 1] << 8 | vram[address + 2] << 16 | vram[address + 3] << 24;
} else if(mode & Half) {
if(mode & Half) {
address &= ~1;
return vram[address + 0] << 0 | vram[address + 1] << 8;
} else if(mode & Byte) {
@@ -24,52 +38,39 @@ auto PPU::readVRAM(u32 mode, n32 address) -> n32 {
unreachable;
}
auto PPU::writeVRAM(u32 mode, n32 address, n32 word) -> void {
auto PPU::writeVRAM(u32 mode, n32 address, n16 half) -> void {
address &= 0x1ffff;
if(Background::IO::mode >= 3 && address < 0x1c000 && address >= 0x18000) return;
address &= (address & 0x10000) ? 0x17fff : 0x0ffff;
if(mode & Word) {
address &= ~3;
vram[address + 0] = word >> 0;
vram[address + 1] = word >> 8;
vram[address + 2] = word >> 16;
vram[address + 3] = word >> 24;
} else if(mode & Half) {
if(mode & Half) {
address &= ~1;
vram[address + 0] = word >> 0;
vram[address + 1] = word >> 8;
vram[address + 0] = half >> 0;
vram[address + 1] = half >> 8;
} else if(mode & Byte) {
//8-bit writes to OBJ section of VRAM are ignored
if(Background::IO::mode <= 2 && address >= 0x10000) return;
if(Background::IO::mode <= 5 && address >= 0x14000) return;
address &= ~1;
vram[address + 0] = (n8)word;
vram[address + 1] = (n8)word;
vram[address + 0] = (n8)half;
vram[address + 1] = (n8)half;
}
}
auto PPU::readPRAM(u32 mode, n32 address) -> n32 {
if(mode & Word) return readPRAM(Half, address & ~2) << 0 | readPRAM(Half, address | 2) << 16;
auto PPU::readPRAM(u32 mode, n32 address) -> n16 {
if(mode & Byte) return readPRAM(Half, address) >> ((address & 1) * 8);
return pram[address >> 1 & 511];
}
auto PPU::writePRAM(u32 mode, n32 address, n32 word) -> void {
if(mode & Word) {
writePRAM(Half, address & ~2, word >> 0);
writePRAM(Half, address | 2, word >> 16);
return;
}
auto PPU::writePRAM(u32 mode, n32 address, n16 half) -> void {
if(mode & Byte) {
word = (n8)word;
return writePRAM(Half, address, word << 8 | word << 0);
half = (n8)half;
return writePRAM(Half, address, half << 8 | half << 0);
}
pram[address >> 1 & 511] = (n16)word;
pram[address >> 1 & 511] = (n16)half;
}
auto PPU::readOAM(u32 mode, n32 address) -> n32 {
+19 -8
View File
@@ -1,7 +1,15 @@
auto PPU::Objects::setEnable(n1 status) -> void {
io.enable[3] = status;
for(auto& flag : io.enable) flag &= status;
}
auto PPU::Objects::scanline(u32 y) -> void {
if(y >= 160) return;
mosaicOffset = 0;
auto& buffer = lineBuffers[y & 1];
for(auto& pixel : buffer) pixel = {};
if(ppu.blank() || !io.enable) return;
if(ppu.io.forceBlank[1] || cpu.stopped() || !io.enable[1]) return; //checks if display conditions will be met next scanline
for(auto& object : ppu.object) {
n8 py = y - object.y;
@@ -60,7 +68,7 @@ auto PPU::Objects::scanline(u32 y) -> void {
if(color) {
if(object.colors == 0) color = object.palette * 16 + color;
buffer[bx].enable = true;
buffer[bx].color = ppu.pram[256 + color];
buffer[bx].color = 256 + color;
buffer[bx].translucent = object.mode == 1;
}
}
@@ -72,28 +80,31 @@ auto PPU::Objects::scanline(u32 y) -> void {
}
}
auto PPU::Objects::run(u32 x, u32 y) -> void {
auto PPU::Objects::outputPixel(u32 x, u32 y) -> void {
output = {};
if(ppu.blank() || !io.enable) {
if(ppu.blank() || !io.enable[0]) {
mosaic = {};
return;
}
auto& buffer = lineBuffers[y & 1];
output = buffer[x];
//horizontal mosaic
if(mosaicOffset >= 1 + io.mosaicWidth) {
mosaicOffset = 0;
if(!mosaicOffset) {
mosaicOffset = 1 + io.mosaicWidth;
mosaic = output;
} else if(!mosaic.mosaic || !output.mosaic) {
mosaic = output;
}
mosaicOffset++;
mosaicOffset--;
}
auto PPU::Objects::power() -> void {
io = {};
for(auto& pixel : buffer) pixel = {};
for(auto& buffer : lineBuffers) {
for(auto& pixel : buffer) pixel = {};
}
output = {};
mosaic = {};
mosaicOffset = 0;
+121 -61
View File
@@ -1,15 +1,5 @@
#include <gba/gba.hpp>
//pixel: 4 cycles
//hdraw: 46 cycle wait period, then 240 pixels (total: 1006 cycles)
//hblank: 226 cycles
//scanline: 1232 cycles
//vdraw: 160 scanlines (197120 cycles)
//vblank: 68 scanlines ( 83776 cycles)
//frame: 228 scanlines (280896 cycles)
namespace ares::GameBoyAdvance {
PPU ppu;
@@ -23,6 +13,10 @@ PPU ppu;
#include "debugger.cpp"
#include "serialization.cpp"
auto PPU::setAccurate(bool value) -> void {
accurate = value;
}
auto PPU::load(Node::Object parent) -> void {
vram.allocate(96_KiB);
pram.allocate(512);
@@ -73,21 +67,63 @@ auto PPU::unload() -> void {
}
inline auto PPU::blank() -> bool {
return io.forceBlank || cpu.stopped();
return io.forceBlank[0] || cpu.stopped();
}
auto PPU::step(u32 clocks) -> void {
Thread::step(clocks);
Thread::synchronize(cpu);
Thread::synchronize(cpu, display);
}
template<u32 Cycle>
auto PPU::cycleLinear(u32 x, u32 y) -> void {
n3 mode = PPU::Background::IO::mode;
if constexpr(Cycle == 0) if(mode <= 1) bg0.linear(x, y);
if constexpr(Cycle == 1) if(mode <= 1) bg1.linear(x, y);
if constexpr(Cycle == 2) if(mode == 0) bg2.linear(x, y);
if constexpr(Cycle == 3) if(mode == 0) bg3.linear(x, y);
}
template<u32 Cycle>
auto PPU::cycleAffine(u32 x, u32 y) -> void {
n3 mode = PPU::Background::IO::mode;
if constexpr(Cycle == 0) if( mode == 2) bg3.affineFetchTileMap(x, y);
if constexpr(Cycle == 1) if( mode == 2) bg3.affineFetchTileData(x, y);
if constexpr(Cycle == 2) if(mode == 1 || mode == 2) bg2.affineFetchTileMap(x, y);
if constexpr(Cycle == 3) if(mode == 1 || mode == 2) bg2.affineFetchTileData(x, y);
}
auto PPU::cycleBitmap(u32 x, u32 y) -> void {
n3 mode = PPU::Background::IO::mode;
if(mode >= 3 && mode <= 5) bg2.bitmap(x, y);
}
auto PPU::cycleUpperLayer(u32 x, u32 y) -> void {
ppu.bg0.outputPixel(x, y);
ppu.bg1.outputPixel(x, y);
ppu.bg2.outputPixel(x, y);
ppu.bg3.outputPixel(x, y);
ppu.objects.outputPixel(x, y);
window0.run(x, y);
window1.run(x, y);
window2.output = objects.output.window;
window3.output = true;
dac.upperLayer(x, y);
}
template<u32 Cycle>
auto PPU::cycle(u32 y) -> void {
if constexpr(Cycle >= 31 && Cycle <= 1005 ) cycleLinear<(Cycle - 31) & 3>((Cycle - 31) / 4, y);
if constexpr(Cycle >= 31 && Cycle <= 1005 ) cycleAffine<(Cycle - 31) & 3>((Cycle - 31) / 4, y);
if constexpr(Cycle >= 31 && Cycle <= 1005 && (Cycle - 31) % 4 == 3) cycleBitmap((Cycle - 31) / 4, y);
if constexpr(Cycle >= 46 && Cycle <= 1005 && (Cycle - 46) % 4 == 0) cycleUpperLayer((Cycle - 46) / 4, y);
if constexpr(Cycle >= 46 && Cycle <= 1005 && (Cycle - 46) % 4 == 2) dac.lowerLayer((Cycle - 46) / 4, y);
step(1);
releaseBus();
}
auto PPU::main() -> void {
cpu.keypad.run();
io.vblank = io.vcounter >= 160 && io.vcounter <= 226;
io.vcoincidence = io.vcounter == io.vcompare;
if(io.vcounter == 0) {
if(display.io.vcounter == 0) {
frame();
bg2.io.lx = bg2.io.x;
@@ -97,58 +133,82 @@ auto PPU::main() -> void {
bg3.io.ly = bg3.io.y;
}
if(io.vcounter == 160) {
if(io.irqvblank) cpu.irq.flag |= CPU::Interrupt::VBlank;
cpu.dmaVblank();
}
step(31);
if(io.irqvcoincidence) {
if(io.vcoincidence) cpu.irq.flag |= CPU::Interrupt::VCoincidence;
}
u32 y = display.io.vcounter;
memory::move(io.forceBlank, io.forceBlank + 1, sizeof(io.forceBlank) - 1);
memory::move(bg0.io.enable, bg0.io.enable + 1, sizeof(bg0.io.enable) - 1);
memory::move(bg1.io.enable, bg1.io.enable + 1, sizeof(bg1.io.enable) - 1);
memory::move(bg2.io.enable, bg2.io.enable + 1, sizeof(bg2.io.enable) - 1);
memory::move(bg3.io.enable, bg3.io.enable + 1, sizeof(bg3.io.enable) - 1);
memory::move(objects.io.enable, objects.io.enable + 1, sizeof(objects.io.enable) - 1);
bg0.scanline(y);
bg1.scanline(y);
bg2.scanline(y);
bg3.scanline(y);
objects.scanline((y + 1) % 228);
dac.scanline(y);
step(46);
if(y < 160) {
if(accurate) {
#define cycles01(index) cycle<index>(y)
#define cycles02(index) cycles01(index); cycles01(index + 1)
#define cycles04(index) cycles02(index); cycles02(index + 2)
#define cycles08(index) cycles04(index); cycles04(index + 4)
#define cycles16(index) cycles08(index); cycles08(index + 8)
#define cycles32(index) cycles16(index); cycles16(index + 16)
#define cycles64(index) cycles32(index); cycles32(index + 32)
if(io.vcounter < 160) {
u32 y = io.vcounter;
bg0.scanline(y);
bg1.scanline(y);
bg2.scanline(y);
bg3.scanline(y);
objects.scanline(y);
auto line = screen->pixels().data() + y * 240;
for(u32 x : range(240)) {
bg0.run(x, y);
bg1.run(x, y);
bg2.run(x, y);
bg3.run(x, y);
objects.run(x, y);
window0.run(x, y);
window1.run(x, y);
window2.output = objects.output.window;
window3.output = true;
n15 color = dac.run(x, y);
line[x] = color;
step(4);
//cycle 31 - start rendering backgrounds
cycles01( 31);
cycles02( 32);
cycles04( 34);
cycles08( 38);
//cycle 46 - start pixel output
cycles64( 46);
cycles64(110);
cycles64(174);
cycles64(238);
cycles64(302);
cycles64(366);
cycles64(430);
cycles64(494);
cycles64(558);
cycles64(622);
cycles64(686);
cycles64(750);
cycles64(814);
cycles64(878);
cycles64(942);
#undef cycles02
#undef cycles04
#undef cycles08
#undef cycles16
#undef cycles32
#undef cycles64
} else {
for(u32 x : range(240)) {
bg0.run(x, y);
bg1.run(x, y);
bg2.run(x, y);
bg3.run(x, y);
cycleUpperLayer(x, y);
dac.lowerLayer(x, y);
}
releaseBus();
step(975);
}
} else {
step(960);
step(975);
}
io.hblank = 1;
if(io.irqhblank) cpu.irq.flag |= CPU::Interrupt::HBlank;
if(io.vcounter < 160) cpu.dmaHblank();
step(226);
io.hblank = 0;
if(++io.vcounter == 228) io.vcounter = 0;
if(io.vcounter == 162) {
if(videoCapture) cpu.dma[3].enable = 0;
videoCapture = !videoCapture && cpu.dma[3].timingMode == 3 && cpu.dma[3].enable;
}
if(io.vcounter >= 2 && io.vcounter < 162 && videoCapture) cpu.dmaHDMA();
}
auto PPU::frame() -> void {
system.controls.poll();
screen->frame();
scheduler.exit(Event::Frame);
}
@@ -160,8 +220,8 @@ auto PPU::power() -> void {
for(u32 n = 0x000; n <= 0x055; n++) bus.io[n] = this;
for(u32 n = 0; n < 96 * 1024; n++) vram[n] = 0x00;
for(u32 n = 0; n < 1024; n += 2) writePRAM(n, Half, 0x0000);
for(u32 n = 0; n < 1024; n += 2) writeOAM(n, Half, 0x0000);
for(u32 n = 0; n < 1024; n += 2) writePRAM(Half, n, 0x0000);
for(u32 n = 0; n < 1024; n += 2) writeOAM(Half, n, 0x0000);
io = {};
for(auto& object : this->object) object = {};
+62 -25
View File
@@ -7,6 +7,8 @@ struct PPU : Thread, IO {
Memory::Writable<n8 > vram; //96KB
Memory::Writable<n16> pram;
bool accurate;
struct Debugger {
//debugger.cpp
auto load(Node::Object) -> void;
@@ -27,12 +29,19 @@ struct PPU : Thread, IO {
} debugger;
//ppu.cpp
auto setAccurate(bool value) -> void;
auto load(Node::Object) -> void;
auto unload() -> void;
auto blank() -> bool;
auto step(u32 clocks) -> void;
template<u32> auto cycleLinear(u32 x, u32 y) -> void;
template<u32> auto cycleAffine(u32 x, u32 y) -> void;
auto cycleBitmap(u32 x, u32 y) -> void;
auto cycleUpperLayer(u32 x, u32 y) -> void;
template<u32> auto cycle(u32 y) -> void;
auto main() -> void;
auto frame() -> void;
@@ -44,12 +53,16 @@ struct PPU : Thread, IO {
auto writeIO(n32 address, n8 byte) -> void;
//memory.cpp
auto readVRAM(u32 mode, n32 address) -> n32;
auto readVRAM_BG(u32 mode, n32 address) -> n32;
auto writeVRAM(u32 mode, n32 address, n32 word) -> void;
auto releaseBus() -> void;
auto pramContention() -> bool;
auto vramContention(n32 address) -> bool;
auto readPRAM(u32 mode, n32 address) -> n32;
auto writePRAM(u32 mode, n32 address, n32 word) -> void;
auto readVRAM(u32 mode, n32 address) -> n16;
auto readVRAM_BG(u32 mode, n32 address) -> n16;
auto writeVRAM(u32 mode, n32 address, n16 half) -> void;
auto readPRAM(u32 mode, n32 address) -> n16;
auto writePRAM(u32 mode, n32 address, n16 half) -> void;
auto readOAM(u32 mode, n32 address) -> n32;
auto writeOAM(u32 mode, n32 address, n32 word) -> void;
@@ -70,18 +83,8 @@ private:
struct IO {
n1 gameBoyColorMode;
n1 forceBlank;
n1 forceBlank[4];
n1 greenSwap;
n1 vblank;
n1 hblank;
n1 vcoincidence;
n1 irqvblank;
n1 irqhblank;
n1 irqvcoincidence;
n8 vcompare;
n16 vcounter;
} io;
struct Pixel {
@@ -89,6 +92,9 @@ private:
n2 priority;
n15 color;
//BG2 only
n1 directColor;
//OBJ only
n1 translucent;
n1 mosaic;
@@ -97,10 +103,15 @@ private:
struct Background {
//background.cpp
auto setEnable(n1 status) -> void;
auto scanline(u32 y) -> void;
auto outputPixel(u32 x, u32 y) -> void;
auto run(u32 x, u32 y) -> void;
auto linearFetchTileMap() -> void;
auto linearFetchTileData() -> void;
auto linear(u32 x, u32 y) -> void;
auto affine(u32 x, u32 y) -> void;
auto affineFetchTileMap(u32 x, u32 y) -> void;
auto affineFetchTileData(u32 x, u32 y) -> void;
auto bitmap(u32 x, u32 y) -> void;
auto power(u32 id) -> void;
@@ -115,7 +126,7 @@ private:
static n5 mosaicWidth;
static n5 mosaicHeight;
n1 enable;
n1 enable[4];
n2 priority;
n2 characterBase;
@@ -147,9 +158,21 @@ private:
n1 hflip;
n1 vflip;
n4 palette;
n16 data;
} latch;
Pixel output;
struct Affine {
u32 screenSize;
u32 screenWrap;
u32 cx;
u32 cy;
u32 tx;
u32 ty;
n8 character;
} affine;
Pixel output[240];
Pixel mosaic;
u32 mosaicOffset;
@@ -162,15 +185,16 @@ private:
struct Objects {
//object.cpp
auto setEnable(n1 status) -> void;
auto scanline(u32 y) -> void;
auto run(u32 x, u32 y) -> void;
auto outputPixel(u32 x, u32 y) -> void;
auto power() -> void;
//object.cpp
auto serialize(serializer&) -> void;
struct IO {
n1 enable;
n1 enable[4];
n1 hblank; //1 = allow access to OAM during Hblank
n1 mapping; //0 = two-dimensional, 1 = one-dimensional
@@ -178,7 +202,7 @@ private:
n5 mosaicHeight;
} io;
Pixel buffer[240];
Pixel lineBuffers[2][240];
Pixel output;
Pixel mosaic;
u32 mosaicOffset;
@@ -210,7 +234,10 @@ private:
struct DAC {
//dac.cpp
auto run(u32 x, u32 y) -> n15;
auto scanline(u32 y) -> void;
auto upperLayer(u32 x, u32 y) -> void;
auto lowerLayer(u32 x, u32 y) -> void;
auto pramLookup(Pixel& layer) -> n15;
auto blend(n15 above, u32 eva, n15 below, u32 evb) -> n15;
auto power() -> void;
@@ -226,6 +253,15 @@ private:
n5 blendEVB;
n5 blendEVY;
} io;
u32 aboveLayer;
u32 belowLayer;
n15 color;
n1 blending;
Pixel layers[6];
u32* line = nullptr;
} dac;
struct Object {
@@ -264,8 +300,9 @@ private:
i16 pc;
i16 pd;
} objectParam[32];
n1 videoCapture = 0;
bool pramAccessed;
bool vramAccessedBG;
};
extern PPU ppu;
+6 -13
View File
@@ -5,18 +5,8 @@ auto PPU::serialize(serializer& s) -> void {
s(pram);
s(io.gameBoyColorMode);
s(io.forceBlank);
for(auto& flag : io.forceBlank) s(flag);
s(io.greenSwap);
s(io.vblank);
s(io.hblank);
s(io.vcoincidence);
s(io.irqvblank);
s(io.irqhblank);
s(io.irqvcoincidence);
s(io.vcompare);
s(io.vcounter);
s(videoCapture);
s(Background::IO::mode);
s(Background::IO::frame);
@@ -34,12 +24,15 @@ auto PPU::serialize(serializer& s) -> void {
s(dac);
for(auto& object : this->object) s(object);
for(auto& param : this->objectParam) s(param);
s(pramAccessed);
s(vramAccessedBG);
}
auto PPU::Background::serialize(serializer& s) -> void {
s(id);
s(io.enable);
for(auto& flag : io.enable) s(flag);
s(io.priority);
s(io.characterBase);
s(io.unused);
@@ -67,7 +60,7 @@ auto PPU::Background::serialize(serializer& s) -> void {
}
auto PPU::Objects::serialize(serializer& s) -> void {
s(io.enable);
for(auto& flag : io.enable) s(flag);
s(io.hblank);
s(io.mapping);
s(io.mosaicWidth);
+1 -1
View File
@@ -17,7 +17,7 @@ auto BIOS::readROM(n25 address) -> n32 {
auto BIOS::read(u32 mode, n25 address) -> n32 {
//unmapped memory
if(address >= 0x0000'4000) {
return cpu.pipeline.fetch.instruction; //0000'4000-01ff'ffff
return cpu.openBus.get(mode, address); //0000'4000-01ff'ffff
}
//GBA BIOS is read-protected; only the BIOS itself can read its own memory
Loaded 100 of 1207 files, more files were not shown because too many files have changed in this diff. Show more