Compare commits

...
322 Commits
Author SHA1 Message Date
jcm 625df94505 n64: Always re-init paraLLEl-RDP from worker thread 2025-07-09 06:48:58 +01:00
jcm 0dc80ee4a2 desktop-ui: Fix data race when loading title on startup 2025-07-08 20:38:47 +01:00
jcm f373fdc165 desktop-ui: Guard changes to emulator video settings 2025-07-07 17:49:49 +01:00
jcm 68f2c94658 desktop-ui: Use Program::Guard to manage program state 2025-07-07 17:49:49 +01:00
jcm 11750b9600 hiro: Adjust GUI run loop frequency 2025-07-07 17:49:49 +01:00
remutro 135cadd32f Use GBC core with N64 transfer pak to allow both GB & GBC saves 2025-07-07 17:49:42 +01:00
invertego f015fffd69 build: #ifdef guard pragmas specific to gcc/clang
This eliminates some warnings compiling with MSVC.
2025-06-30 11:39:31 +01:00
User aa7260a58d s3511a: port alarm handling from WonderSwan core 2025-06-30 11:39:22 +01:00
User cdd551f122 s3511a: add comments for registers with 0-byte payloads 2025-06-30 11:39:22 +01:00
User f3ce7952f6 gba: make S3511A a shared component 2025-06-30 11:39:22 +01:00
User 9b1eb2e2f9 gba: use same variable for input and output of RTC SIO pin 2025-06-30 11:39:22 +01:00
User c337ba258f gba: RTC status bit 7 is cleared on write, not read 2025-06-30 11:39:22 +01:00
User 6f16c5c17e gba: RTC should not be aware of GPIO direction 2025-06-30 11:39:22 +01:00
User b494705ad7 gba: fix RTC power-on state 2025-06-30 11:39:22 +01:00
User 371ba7b136 gba: implement GPIO output buffer 2025-06-30 11:39:22 +01:00
User fb685afa70 gba: initial RTC implementation 2025-06-30 11:39:22 +01:00
jcm f3ff75feb1 desktop-ui: Synchronize access to emulator configuration shown in status bar 2025-06-29 07:48:16 +01:00
jcm 5211e6c56d ares: Use atomic to synchronize run-ahead setting 2025-06-29 07:48:16 +01:00
invertego e3c5cfb44d ps1: make mute bit apply to reverb voices 2025-06-28 08:47:02 +01:00
invertego c95b48d95f ps1: make save states robust across ares launches
The CPU serialization logic would sometimes write pointers to save
states. Needless to say, this was not very compatible with saving and
loading states across separate runs of the ares process.
2025-06-28 08:46:36 +01:00
invertego 136afead52 ps1: represent spu noise as a signed 16-bit quantity 2025-06-27 12:17:26 +01:00
jcm 0865680da1 CI: Pin commit hashes for all third-party actions 2025-06-26 09:59:57 +01:00
jcm 08811ee3cb build: Use CMake build type for default launch configuration in Xcode 2025-06-26 09:59:57 +01:00
jcm b79ed895ff build: Prefer built-in setting for LTO on Xcode 2025-06-26 09:59:57 +01:00
jcm ece74e44e4 Show explicit Ccache status messages 2025-06-26 09:59:57 +01:00
TascoDLX b1c69c9f3f md: add cpu wait for apu bus access 2025-06-25 06:40:35 +01:00
Luke Usher 4c42273a07 ps1: DICR bit 15 is readable 2025-06-24 10:41:53 +01:00
Luke Usher ac58451996 nall: allow the use of VT100 escape sequences on Windows when supported and treat console output as utf8 2025-06-24 10:41:01 +01:00
Luke Usher 325c0ed876 ps1: use physical addresses as early as possible 2025-06-24 10:41:00 +01:00
Luke Usher f89777d8cc ps1: allow loading of executables with ps-exe extension 2025-06-24 10:41:00 +01:00
invertego f0fd4c0bd2 ps1: fix dma interrupt flag calculation
The topmost bit of the DICR (DMA Interrupt) register should not
influenced by the per-channel interrupt enable bits. This flaw was
masked in fast boot mode, as it allows title code to begin execution in
a pristine state unlike what the BIOS leaves behind.

With this change, the titles that were "fixed" by enabling fast boot
mode can now be launched with it disabled.
2025-06-24 07:02:17 +01:00
png183 a3d8db1c2a arm7tdmi: implement R15 misalignment and clean up LDM/STM (#2058)
Allows bit 1 of R15 to be set in ARM mode.

The updated LDM/STM implementations are functionally identical to the
previous versions, but are significantly shorter and require less
special-casing.
2025-06-23 11:21:30 +01:00
Luke Usher 073d7a5375 desktop-ui: status bar overhaul
The status bar now shows the loaded system configuration when there are no messages to display.
When GDB is enabled, debug status will show instead.
2025-06-13 12:13:25 +01:00
Luke Usher 264a1baafa desktop-ui: simplify region detection; fix "NTSC" base region and NTSC-DEV, etc 2025-06-13 11:42:14 +01:00
Luke Usher 645be6ab9b ui: implement order of region preferences= 2025-06-11 18:59:55 +01:00
Luke Usher 67fc2b1073 fc: fix database to allow running PAL/NTSC games in both supported modes 2025-06-11 15:03:16 +01:00
png183 46b1991f8f gba: prefetcher timing improvements (#2051)
Fixed a bug where the prefetcher was restarting too early upon being
emptied, and implemented a timing edge case involving simultaneous
accesses from the CPU and prefetcher.
2025-06-11 10:06:31 +01:00
Luke Usher c9dfe8a1b9 gb: g/hdma takes 4 clocks to setup + 32|64 clocks depending on mode 2025-06-09 16:55:02 +01:00
Luke Usher af07e1f863 gb: hdma should be triggered on the rising edge of the combined hblank & hdmaActive signal 2025-06-09 16:55:02 +01:00
jcm b624fadd75 desktop-ui: Acquire program mutex for hotkeys affecting state (#2048)
Fixes an oversight where hotkeys that affected emulated system state
were not acquiring the program mutex.

Should fix #2045
2025-06-06 17:21:40 +01:00
png183 46209710d7 gba: do not advance IRQs during DMA (#2047)
Improves timings regarding interactions between the IRQ pipeline and
DMA, allowing ares to pass more of Alyosha's new test ROMs.
2025-06-05 07:26:20 +01:00
Luke Usher 90eb0df7d7 gb: HDMA issued during hblank (mode 0) should be processed immediately
Fixes:
Little Mermaid II, The - Pinball Frenzy
3-D Ultra Pinball - Thrillride

Likely others
2025-06-04 11:19:53 +01:00
jcm 64c9751dc5 desktop-ui: Threading fixes (#2046)
* Acquire the program mutex when updating audio sync settings to prevent
a possible crash in some audio drivers
* Pause emulation while showing driver confirmation modals to prevent
interference from the UI thread calling `ruby::audio.clear()` during the
modal state, and also because pausing the application for a modal is a
normal pattern
* Restore a workaround when loading Arcade systems via the game browser
window that prevented a crash
2025-06-03 22:33:37 +01:00
jcm 54e3479708 desktop-ui: Initialize tools window before program (#2044)
When loading a ROM via a startup argument, `Program` requires access to
elements that are initialized as part of the Tools window. Thus, make
sure the Tools window is fully loaded before creating `Program`.

This restores the load order prior to the threading rework. An earlier
version of the threading rework created the program mutex differently,
which is why the load order was modified in the first place
(incidentally rather than intentionally).

Fixes #2043
2025-06-02 17:26:19 +01:00
png183 9186ec0201 arm7tdmi: specify undefined instructions more strictly (#2042)
- Adds instruction encodings for BX with bit 21 clear, and for an
undocumented `mov rd, rn` instruction
- Uses specific encodings for undefined instructions, rather than
binding them to unused encodings, and then asserts that all encodings
have been bound
2025-05-31 18:20:05 +01:00
png183 64196caef8 gba: step CPU 1 cycle at a time while halted (#2041)
Removes a speedup in the GBA core that was detrimental to accuracy.
Testing on Linux, the performance cost is more than offset by the recent
UI threading rework.
2025-05-30 20:34:53 +01:00
jcm 1d0d6177a5 desktop-ui: Threading rework (#1906)
Rearranges ares's main run loop, putting emulation in its own dedicated
thread that is separate from the main/GUI thread. This updates ares to
somewhat more modern application practices. This rework should have an
array of benefits, including increased UI responsiveness, improved
energy efficiency/performance, and increased compatibility with various
modern APIs and frameworks for rendering, input, and audio.

## Details

Generally, this PR implements a fairly simple approach to threading,
using `nall::thread`'s pthread-like semantics and several basic
recursive mutexes. For this initial implementation, we use very coarse
locking on the emulation thread, combined with very limited access to
the emulator state from the main and other ares threads, allowed to
occur between emulator run loop iterations. Synchronization on the
emulator state is managed via `programMutex`.

Since this mutex is held for the duration of the primary work loop,
including while the thread is suspended, the GUI thread should try to
never acquire the program mutex unless absolutely necessary. Doing so
with regularity will incur a severe UI responsiveness penalty. For
destructive updates like driver settings updates, memory writes, and
game loads/unloads, we acquire it. For other cross-thread communication,
we try to synchronize using other methods that do not incur a
significant performance penalty.

Window resizes triggered via the emulation loop synchronize with the
`_needsResize` atomic. Status messages are passed by acquiring the
`messageMutex`. `vBlanksPerSecond` is also now an `atomic<u64>`.

Input continues to poll on the main thread for compatibility with
existing code. Access to the input system is managed via `inputMutex`.

### Known Issues

Draft status as this is still a work in progress, but PRing now for
visibility, feedback, and to consolidate any issue tracking. There are
likely kinks left to work out; testing is appreciated.

~~- Cores are loaded on the main thread before being run on the emulator
thread; this causes issues for paraLLEl-RDP, which expects that the
thread to initialize Vulkan is also the thread that will make RDP
calls.~~ Addressed.

~~- Memory editor currently does not have access to the program mutex;
reads and writes are unsynchronized.~~ Addressed; memory editor
synchronizes on writes but reads occur in a thread-unsafe fashion.

~~- The Clang thread sanitizer still reports a couple data races in
Metal and OpenGL; further testing with other Ruby drivers is needed to
make sure resource access is properly managed, particularly with respect
to the output framebuffers.~~ A larger examination of locking in other
parts of ares is probably necessary, but I think out of scope for the
first iteration of this rework.

- The gdb server seems to still be working fine, but could probably use
more testing.
2025-05-30 09:48:22 +01:00
jcm 421b7abf96 build: Fix build on macOS 10.15 (#2027)
[Build docs
state](https://github.com/ares-emulator/ares/wiki/Build-Instructions-For-macOS)
that we support building on macOS 10.15. A couple things broke since
that was written:


https://github.com/ares-emulator/ares/commit/6cc9f5a416ec9b0077fc0f50912b1af96987cdf5
broke because AppleClang 12.0 thinks that `step` is referring to the
function called `step` rather than the argument provided to the
function.


https://github.com/ares-emulator/ares/commit/c287c1b22501152342746ada4c988049715a1934
broke because the availability macro was not written correctly.


https://github.com/ares-emulator/ares/commit/4fc09438d22b02ea23d70ff96661e24151165ef6
broke because we made an inappropriate replacement when replacing
deprecations: `NSRegularSquareBezelStyle` should have become
`NSBezelStyleRegularSquare`; `NSBezelStyleFlexiblePush` resolves to the
same appearance, but is unavailable in the SDK included with Xcode 12.4.
2025-05-29 18:01:11 +01:00
thekovic 7e9df5858d n64: Improve labels for internal resolution upscaling options (#2026)
The SD/HD/UHD options represent scaling the internal N64 resolution to
1x/2x/4x. Even for a title running at 640x480, this results in 1280x960
and 2560x1920 which doesn't match the meaning of HD/UHD. Games running
at lower resolutions give even more out of whack results. New label
communicates more explicitly what the option actually does.

I didn't change the string used to serialize this option in
`settings.bml`. Feedback welcome on whether I should do that.
2025-05-29 18:01:04 +01:00
Luke Usher 69381f7c54 ms: improve header validation; fixes many NTSC-J titles being detected as international 2025-05-29 12:51:24 +01:00
png183 8f55894d65 arm7tdmi: add support for more undocumented instruction fields (#2039)
Adds unused bits to MUL and MRS, and adds support for undocumented STR
counterparts to LDRSH and LDRSB.
2025-05-29 10:01:44 +01:00
jcm 4e1435be8a ruby/metal: Zero-initialize librashader handles (#2038)
Metal checks whether librashader handles are non-null during
deinitialization to determine whether to call librashader's `free`
functions on them.

If the handles are initialized to contain junk data, they will be
non-null but `free` will fail, causing a crash during the deinit that
occurs prior to any initialization of the video driver.

On Apple Silicon, the system malloc implementation provides something of
a guarantee that heap allocations are zero-initialized, but this proves
to not always be the case in practice. There are also no (or fewer) such
guarantees on x86_64.

On OpenGL, these pointers were already being zero-initialized.
2025-05-29 10:01:14 +01:00
png183 cf0c21e15a arm7tdmi: improved handling of PSR edge cases (#2036)
When the CPSR mode field is set to an invalid mode, SP (R13), LR (R14),
and SPSR are not mapped to any register. Therefore, writes to them
should fail, and reading them should return zero (or 0x00000010 in the
case of SPSR).

Update: Also implemented a new edge case for BX instructions, where
setting bit 22 causes SPSR to be modified rather than CPSR.
2025-05-26 09:16:36 +01:00
png183 e10ce79153 arm7tdmi: add undocumented SWP encodings (#2032)
Instruction bits 23, 21, and 20 do not need to be zero for a SWP
instruction to be successfully decoded.
2025-05-24 19:16:10 +01:00
jcm ad7b83b604 build: Miscellaneous fixes (#2033)
* Fix a regression where the application manifest was not embedding
properly on Windows, leading to various problems including incorrect UI
styling and DPI settings
* Fix an issue where we would fail to parse a canonical version from a
`git describe` string without a suffix
2025-05-24 19:15:39 +01:00
jcm 53f3b6a2a2 Update dependencies to 2025-05-22 release (#2029)
* Update SDL to 3.2.14, containing miscellaneous bugfixes
* Update librashader to 0.8.1, which should address a rare crash with
bad shader caches on Windows
* Update slang-shaders to its master branch contents as of 5-21
(8c630e0d3234d93b6c2bc847371f86aa4e535686)
* Update MoltenVK to version 1.3.0
2025-05-22 19:34:36 +01:00
Alexander Chen b630377ddc hiro/cocoa: Add Edit Menu, refactor menu creation (#2024) 2025-05-18 08:35:00 +01:00
User 24a9c00ae7 arm7tdmi: finish coprocessor interface 2025-05-18 08:34:06 +01:00
User b5488aad82 arm7tdmi: simplify coprocessor interface 2025-05-18 08:34:06 +01:00
User 5f782419ae arm7tdmi: implement CDP instruction 2025-05-18 08:34:06 +01:00
User 7d5c6d2561 arm7tdmi: implement MCR instruction 2025-05-18 08:34:06 +01:00
User 585e43a94c arm7tdmi: implement MRC instruction 2025-05-18 08:34:06 +01:00
Luke Usher 28ab75242f cmake: keyboard.cpp should not have been duplicated as an included source 2025-05-17 13:58:26 +01:00
jcm 4dd7a1f5fe build: Fix up artifact metadata to include version info, copyright 2025-05-17 13:55:29 +01:00
jcm 756ea5b704 build: Do not require tags, add unofficial versioning scheme 2025-05-17 13:55:29 +01:00
jcm 7c051bae0b Update CMake policy version, add old Finder metadata to .gitignore (#2019)
Add explicit support for CMake 4.0 version policies; the only change
required is to remove a superfluous/invalid POST_BUILD designation from
Linux bundling code.

Also add .DS_Store to the .gitignore, since developers may possibly
still be on systems old enough to litter these everywhere.
2025-05-16 19:23:55 +01:00
Luke Usher edfc6b5fb0 sg: SC-3000 keyboard support 2025-05-16 19:19:47 +01:00
Luke Usher cdc0633fdd sg: properly handle software with on-cart *volatile* ram 2025-05-16 18:07:41 +01:00
Luke Usher 71facd2e14 cmake: add missing sc-3000.cpp 2025-05-16 17:15:37 +01:00
Luke Usher af95d2b760 sg: preliminary sg-3000 emulation (no keyboard yet) 2025-05-16 17:11:56 +01:00
Luke Usher f4f48eb4b9 sg: fix that base SG-1000 doesn't use a PPI
The PPI chip is only present in SG-1000A (Arcade Board) and SC-3000
2025-05-16 14:52:22 +01:00
Luke Usher 667827ab00 sg: IO port B bits 3-6 are active low, 7 is active high 2025-05-16 14:44:07 +01:00
Luke Usher 70480452a8 i8255: implement BSR mode 2025-05-16 14:43:22 +01:00
png183 a70acad605 arm7tdmi: fix failed assertion in debug builds (#2016)
Fixes an assertion that was failing because of an oversight in #2007
regarding ARM7TDMI BX instruction decode bits.
2025-05-15 17:58:47 +01:00
png183 dca8745f83 arm7tdmi: implement more undocumented fields in BX and MSR instructions (#2011)
Adds shifter fields to MSR, and a CPSR mask field to BX.
2025-05-14 13:30:22 +01:00
png183 fabbdc8d8f arm7tdmi: branch instruction fixes (#2007)
Fixed an issue where an undefined opcode was being treated as an
unconditional branch in Thumb mode, and added a destination register
field to ARM mode BX instructions.
2025-05-09 07:36:00 +01:00
png183 1a79a0aae0 gba: various APU improvements (#1997)
- Fixes an edge case involving overflowing audio FIFOs
- Slight FIFO channel timing improvements
- Prevents most APU registers from being written while audio is disabled
- Fixes writing to wave RAM while audio is disabled
2025-05-06 10:34:52 +01:00
jcm de066b1ea2 build: Improve version handling (#1995)
ares' build system tries to always have version information available
for debuggability and build tracking. It depends upon the presence of
Git to provide version information, since Git is the version control
system used by the project.

When distributing tarballs of ares, however, no `.git` directory and no
inherent version information is included in-tree, which causes the build
to fail with a vague fatal error after failing to derive a version for
itself.

Since we would like building a tarball to be at least possible with
minimal fuss, we should provide some version information inside a tar
archive served by GitHub. This PR uses Git's
[export-subst](https://git-scm.com/docs/gitattributes#_export_subst)
attribute to automatically bundle version information when `git-archive`
is run against the repository, as is done when the GitHub API serves a
tar archive of a given release, branch or commit. The build system will
check for the presence of this file if it finds that there is no `.git`
directory at the root of the repository.

This PR also improves the version handling in general to better support
semantic version strings of the form `v123.x.y`, in case future releases
of ares require hotfixes or minor versions.
2025-05-05 14:50:07 +01:00
png183 c185fbd66e gba: reduce audio FIFO size from 32 to 28 bytes (#1963)
Closes #1869.
2025-05-01 11:54:09 +01:00
Alexander Chen dae8db9883 Edited insert to fix bug with "result" variable (#1961)
Fixed result such that insert(std::.....) actually updates result as it
is supposed to.

The change is occured in ares/nall/nall/set.hpp, line 83
2025-04-30 16:03:19 +01:00
jcm 4c4b2a5e5a CI: clangarm64 Windows to aux, clang-cl-arm64 to primary (#1960)
The [Windows signing action used by
ares](https://github.com/Dana-Prajea/code-sign-action) fails under
clangarm64 due to having the wrong path for `signtool.exe`.

This PR swaps the clang-cl arm64 Windows build back into the
primary/nightly workflow until we have a fix for clangarm64 codesigning.
2025-04-29 19:32:35 +01:00
png183 510ccf01d7 gba: add option to enable Game Boy Player (#1856)
Re-adds support for Game Boy Player rumble, with a UI toggle to
enable/disable the feature.
2025-04-29 18:44:46 +01:00
Luke Usher aab2fdf9b2 ps1: missed cmakelists in previous commit 2025-04-29 16:31:08 +01:00
Luke Usher e2d7106a6c ps1: remove the buggy recompiler while we improve overall accuracy
It may be replaced in future, but it introduces too many bugs in its current form.
2025-04-29 13:53:37 +01:00
Luke Usher 1598f67506 ps1: fix VRAMtoCPU transfers 2025-04-29 13:53:37 +01:00
Luke Usher 5d3f614c63 ps1: fix boot of discs without Sony copyright string (XPloder, etc) 2025-04-29 13:53:37 +01:00
Luke Usher 8ef16dfbd9 ps1: fix handling of CE bits of COP0.CAUSE
All tests in psxtest_cpu and psxtest_cpx now pass (when using the interpreter)
2025-04-29 13:53:37 +01:00
User 701cfb7b13 gba: fix erroneous EEPROM zero-initialization 2025-04-29 12:27:42 +01:00
jcm ae121d7377 build: Add arm64 runners to CI, fix msys2 clangarm64 build 2025-04-29 12:27:31 +01:00
remutro ed1e34c74e remove errant NALL_NOINLINE macro from SH2 instructions 2025-04-29 12:26:15 +01:00
Tim Hentenaar 728105b28e ps1: gpu: macro -> constexpr 2025-04-23 09:43:14 +01:00
Tim Hentenaar 3d88e24559 ps1: gpu: Ensure hi >= lo when calling std::clamp() 2025-04-22 13:41:06 +01:00
Adrian Siekierka a61ce6449f ws: support 8-bit bus width ROMs 2025-04-22 11:05:26 +01:00
jcm 63aa9ec5e4 hiro: Use GTK native file dialogs for portal compatibility 2025-04-21 09:49:36 +01:00
remutroandjcm 50e42627e2 Update mia/medium/super-famicom.cpp
Explicit cast so we hit the right constructor.

Co-authored-by: jcm <[email protected]>
2025-04-18 19:01:30 +01:00
remutro 3a46652b15 [SNES] Remove unnecessary additional string allocation 2025-04-18 19:01:30 +01:00
remutro 7528feabe8 [SNES] Update special case Sufami Turbo handling for Fuwafuwa Panic 2025-04-18 19:01:30 +01:00
remutro e57a80ea1b [SNES] Fix loading of some games using firmware by removing unnecessary data definition/reference to rom 2025-04-18 19:01:30 +01:00
User 4c0a03b35a gba: approximate PRAM access stalls in scanline renderer 2025-04-18 19:00:16 +01:00
jcm a247271e35 CI: Preserve symlinks in artifacts 2025-04-10 21:18:40 +01:00
jcm d61cfa905a Update ares-deps to 2025-04-09 release
Includes:
* Stop vendoring the librashader header on Linux
* deps.windows: Update librashader to 0.6.3
* deps.macos: Update librashader to 0.6.3
* Update slang-shaders to ref 25311dc
* Pin Rust nightly to version contemporary with librashader version
* Establish macOS deployment targets
* deps.macos: Update SDL to 3.2.10
* deps.windows: Update SDL to 3.2.10
2025-04-10 14:48:52 +01:00
jcm 9987bf18b2 ruby: Update to SDL3 2025-04-10 14:48:49 +01:00
Adrian Siekierka 8a80d32519 ws: PPU palette 4-7, 12-15 bit 0-2 reads as zero 2025-04-08 17:07:12 +01:00
remutro 5d0de5fbb3 Update MD serialization.cpp
Serialization for the MD, specific to the ym2612 audio implementation was changed, but there wasn't a version bump. This corrects this missing contribution.
2025-04-04 07:18:49 +01:00
jsgroth f06168e3f5 ym2612: fix LFO AM enabled bit not functioning 2025-04-04 06:52:02 +01:00
Adrian Siekierka 828f847efe ws: fix RTC cartridge protocol emulation 2025-04-03 18:36:34 +01:00
jcm d8c997ca8a build: Enable CHD support via build option 2025-04-03 10:47:15 +01:00
jcm 93137b76b4 mia: Add generic CD data sector read method 2025-04-03 10:47:15 +01:00
jcm b889aff3d4 desktop-ui: Don't show missing firmware error twice 2025-04-02 10:42:35 +01:00
Giovanni Bajo 70f3bfa00c n64: disable RDP readbacks from super-sampled image
This fixes some tests in the official RDP testsuite
2025-04-01 17:53:16 +01:00
User d942746f74 gb: implement undocumented PCM12 and PCM34 registers 2025-03-31 18:52:41 +01:00
jcm 1c05456bec libco: Define LIBCO_MPROTECT by default on aarch64 2025-03-27 15:36:11 +00:00
User 240363d31a gba: add renderingCycle to scanline renderer 2025-03-27 10:37:54 +00:00
User ebb3bcb37b gba: improve handling of mid-scanline writes to linear background scroll registers 2025-03-27 10:37:54 +00:00
remutro ab14fb1d10 [MS] Update PAL only entries in mia DB 2025-03-26 14:32:33 +00:00
User 7ba94fe7e4 gba: override save type in known problematic cases 2025-03-24 07:28:00 +00:00
jcm 69ea086d95 build: Remove invalid arguments from custom commands 2025-03-24 07:27:40 +00:00
jcm a510ac7e55 build: Don't search for usbhid on non-BSD 2025-03-24 07:27:40 +00:00
jcm ac98fd8d9c build: Fix macOS SDK detection for CMake 4.0 2025-03-24 07:27:40 +00:00
remutro 122820753e Add DB entry for Back to the Future III which was PAL only 2025-03-20 11:59:56 +00:00
remutro e355fbe88c [N64] Fix Id for Rampage 2 - Universal Tour in DB 2025-03-20 11:59:49 +00:00
Adrian Siekierka c1efa05d65 ws: fix regression in APU logic 2025-03-16 17:46:58 +00:00
Adrian Siekierka da071246fe v30mz: make I/O access timing marginally more accurate 2025-03-15 15:49:37 +00:00
Giovanni Bajo cca0ecf202 n64: add IPL2 checksum failure as accuracy flag
As part of the boot security, IPL2 (run by CPU), PIF and CIC collaborate
to verify that the IPL3 (stored at the beginning of the ROM) is valid
and not tampered, by running a checksum. If the checksum is invalid,
the console is halted immediately.

Ares emulates this behavior correctly. Sometimes, though, it might be
useful for development purposes to let some ROM boot even with a failing
checksum. Given that disabling the check was non-obvious, I'm adding
an accuracy compile-time flag for now.
2025-03-15 15:49:28 +00:00
remutro 17aee9071d Fix check for pif rom when loading Aleck64 games 2025-03-15 15:49:14 +00:00
User b92ae8a14c gba: improve linear background VRAM access timings 2025-03-15 07:59:34 +00:00
jcm 4ae42b2d44 desktop-ui: Fix up app icon, macOS asset compilation 2025-03-13 20:01:42 +00:00
Adrian Siekierka 2a11da200d ws: APU accuracy fixes
- the noise LFSR reset bit takes effect immediately
- channel period counters tick only when they're enabled, including
  if channel 2 is in voice mode or channel 4 is in noise mode
- the noise LFSR only ticks if channel 4 is enabled in noise mode
2025-03-09 21:32:21 +00:00
Giovanni Bajo cbf4a939aa n64: allow booting ROMs with non-standard PI DOM1 parms in the header
All commercial ROMs in N64 have the value 0x80371240 in the first 4
bytes. This has long been used by emulators both as a magic number to
"detect a N64 rom", and as a way to detect endianess of the dump.

In reality, the first byte (0x80) is unused/ignored by the console, while
the other 3 (0x371240) are just parameters used to configure cartridge
access (basically, ROM speed). There's absolutely nothing that prevents
a ROM with other values to boot. Ares currently fails to honor this
by refusing booting ROMs with different values, but this is just wrong.

To fix this, we change approach and use the CIC detection algorithm to
also detect the endianess, given that it's based on a checksum match.
If we can't find a match, we tried the two common types of byteswaps,
hoping to find a match. Eventually, we fallback to assume it's a
big-endian dump, and needs the common CIC-6102.

This means that analyze() will now only reject ROMs with size lower
than 4 KiB, but that's correct. Given that 4 KiB are loaded by the
IPL2, we assume that minimum size is required. Besides that, there is
nothing else in the ROM that can be used to "detect" a N64 ROM, so
it's correct to just let it boot and see what happens.
2025-03-09 19:20:31 +00:00
Adrian Siekierka d10a8498e2 ws: clear serial IRQs if serial block is disabled 2025-03-09 19:19:57 +00:00
Giovanni Bajo 2eb6bf6df8 gamepad: bank switch command must be ignored for single-bank paks 2025-03-05 12:21:44 +00:00
Cuyler36 35ede44b80 Support dynamic bank counts for N64 Contorller Paks 2025-03-05 12:21:44 +00:00
Giovanni Bajo 0c011fb2d4 n64: add O.D.T. to gamelist 2025-03-05 12:21:30 +00:00
Giovanni Bajo a006ef97e7 vi: make sure we refresh the screen even when VI is disabled 2025-03-04 20:07:46 +00:00
User 14a4f32997 gba: perform VRAM accesses in bitmap and affine modes even when no pixel is rendered 2025-03-04 20:06:28 +00:00
Adrian Siekierka 25c1e281cc v30mz, ws: fix HLT regression 2025-03-03 22:47:01 +00:00
invertegoandpng183 3ee7556bb7 arm7tdmi: add missing idle cycles
Co-authored-by: png183 <[email protected]>
2025-03-03 13:15:10 +00:00
invertegoandpng183 a5b11b13d0 arm7tdmi: move to status register bit 4 fix
Co-authored-by: png183 <[email protected]>
2025-03-03 13:15:10 +00:00
invertego 01e6cc1443 arm7tdmi: thumb carry flag fixes 2025-03-03 13:15:10 +00:00
invertegoandpng183 f5dace0a0f arm7tdmi: r15 fixes
Co-authored-by: png183 <[email protected]>
2025-03-03 13:15:10 +00:00
invertego 6b5ebb2882 arm7tdmi: fix disassembler mnemonic 2025-03-03 13:15:10 +00:00
Adrian Siekierka 140782662b v30mz: breaks are also delayed by one instruction 2025-03-02 18:13:58 +00:00
Adrian Siekierka 3daec1184a v30mz, ws: fix interrupt triggering edge cases on interrupt flag change 2025-03-02 18:13:58 +00:00
Adrian Siekierka 7e4386c1bf v30mz: fix interrupt triggering incorrectly around segment move instructions 2025-03-02 18:13:58 +00:00
Adrian Siekierka 8eba8ad784 ws: make level interrupts take immediate effect 2025-03-02 18:13:58 +00:00
png183 08377d02e2 gba: update list of game codes that require mirroring 2025-03-02 18:13:11 +00:00
Luke Usher ea4ad6890a md: 32X display is offset by approx 3.25 pixels to the right in H32 mode 2025-02-27 14:07:21 +00:00
Luke Usher 50be2e4e63 fc: add delay when changing FDS disk state 2025-02-27 11:48:05 +00:00
jcm effc5614bc CI: Align MSYS2 git line ending settings with system git 2025-02-23 14:47:32 +00:00
jcm 5f81464857 misc: CMake formatting pass 2025-02-22 08:50:47 +00:00
jcm bd8442605e build: Move Linux librashader path hint to package finder 2025-02-22 08:50:47 +00:00
jcm da312032de build: Prevent macOS deployment target being modified during auto-regeneration 2025-02-22 08:50:47 +00:00
jcm c509dd3964 Remove CRLFs from ares/n64/CMakeLists.txt 2025-02-22 08:50:47 +00:00
jcm 10a4d480de CI: Unset draft status on tagged releases 2025-02-22 08:50:47 +00:00
User 8c3ead7cb0 gba: latch lower ROM address lines during burst transfer 2025-02-22 08:50:32 +00:00
jcm 1b36d47554 ruby: SDL2 input fixups 2025-02-21 08:37:07 +00:00
jcm 2c940b03a1 nall: Retrieve executable path more reliably 2025-02-21 00:16:50 +00:00
User 7a5174a712 gb: tick timer on falling edge 2025-02-19 18:03:06 +00:00
remutro 274d6eb9a5 Allow for trimmed and padded versions 2025-02-19 18:02:56 +00:00
remutro de0cb099cb Update sha256 for Wonder Boy in Monster World (USA, Europe) for proper eeprom assignment 2025-02-19 18:02:56 +00:00
jcm 32fd70f7c7 build: Enable system library semantics for nall in other targets 2025-02-19 18:02:47 +00:00
Luke Usher b2251305c0 md: always sync core MD components regardless of reduced sync
Fixes VDP H/V tests in testpico when running as a 32X rom.
2025-02-18 14:25:38 +00:00
FitzRoyX 25a2602300 Update README.md 2025-02-18 08:35:00 +00:00
FitzRoyX 4480f7adec Update README.md 2025-02-18 08:35:00 +00:00
jcm 4197502402 nall: Resolve all file paths passed on command line 2025-02-18 08:34:42 +00:00
TascoDLX fb96de3eef mcd: fix subcpu reset behavior 2025-02-18 08:31:56 +00:00
Luke Usher 54c898f199 pak: saveName() needs to call name(), in case it was overridden. 2025-02-17 17:57:26 +00:00
TascoDLX e48b208de2 ym2612: fix timer behaviors 2025-02-17 12:07:24 +00:00
TascoDLX a9f9fd90e7 m32x: fix regs & reset state 2025-02-17 12:07:24 +00:00
TascoDLX deb8830c82 md: fix vdp irq timings 2025-02-17 12:07:24 +00:00
Adrian Siekierka 58af8cb64b ws: First pass at "mono" model color emulation. 2025-02-16 13:17:41 +00:00
TascoDLX c9285b5289 m32x: fix pwm serialization 2025-02-12 06:28:23 +00:00
jcm 4fc09438d2 misc: Address macOS deprecation warnings 2025-02-11 21:36:32 +00:00
jcm a0a7a53b32 build: Increment macOS deployment target to 10.15 2025-02-11 21:36:32 +00:00
User 90f1425b8e Simplify prefetcher logic 2025-02-10 20:47:44 +00:00
User 9f4446061d Initial commit 2025-02-10 20:47:44 +00:00
jcm 32e58943f0 build: Adjust CI push workflow to properly run on all branches 2025-02-10 18:03:40 +00:00
jcm bc116e70e1 build: Add legacy zconf header to .gitignore 2025-02-10 18:03:40 +00:00
jcm 992e1c08cb misc: Use shortened copyright string in About dialog 2025-02-10 18:03:40 +00:00
jcm 9dcc1a39d3 build: Statically link libc++ when using GCC on Windows 2025-02-10 18:03:40 +00:00
Luke Usher 9bbcf638dd gb: use "Game Boy" save path for both GB and GBC
Fixes using the same rom file on both GB and GBC hardware without losing save-data between them
Fixes Pokemon Stadium when loading a .gbc rom (the Transfer Pak only used the GB path)

Existing users using a custom save game path will have to manually move their saves from "Game Boy Color" to "Game Boy"
Users using the default "Save alongside rom files" will not have to take any action.
2025-02-10 16:18:42 +00:00
Luke Usher d6c8d36770 md: fix 32x blending when MD is in H32 mode 2025-02-10 12:54:49 +00:00
jcm c19cf47803 hiro/cocoa: Ensure trailing slash in directory picker result 2025-02-10 09:45:15 +00:00
remutro 1d5a5aef83 remove accidentally introduced space in line with no change 2025-02-09 18:46:25 +00:00
remutro 64ec01bd57 Proper 32X region header processing for licensed games 2025-02-09 18:46:25 +00:00
Luke Usher 82b1e88ec1 sfc: fix typos in sub-rom loading
Fixes Super Game Boy
Fixed Sufami Turbo
Fixes Satellaview/BS Memory Pak
2025-02-07 23:25:43 +00:00
Vincent Cunningham a592dc24d2 ci: Ignore nightly tag for versioning 2025-02-07 18:40:12 +00:00
Luke Usher 976b9828b6 md: Fix new emulator hang/crash in SRB2 32X port 2025-02-07 12:09:04 +00:00
Luke Usher 7f625b6348 md: more 32X PEN=0 stalls; cleaner multi-device sync 2025-02-07 11:51:48 +00:00
Luke Usher 23a9d66924 md: stall m68k when accessing 32x palette when PEN=0
Fixes colours in Chaotix
2025-02-07 11:37:52 +00:00
TascoDLX e4e9044097 m32x vdp fixes
- SH2 memory windows have been adjusted. The framebuffer areas must be mirrored up to 0x5ffffff -- fixes Toughman Contest backgrounds.
- VDP FEN & PEN flags are closer to accurate but still missing some finer timing details.
- FEN/PEN status may block vdp memory accesses. The docs seem to indicate that accesses may be held in wait until a status change, but thats not totally clear (nor validated?). For now, these accesses are blocked and logged in debug.
- FM setting (framebufferAccess) only allows vdp access by either 68k or SH2-side, so additional guards have been inserted for cram/framebuffer accesses. VDP reg accesses should be blocked as well according to docs, but this aspect needs to be reviewed.
- VDP reg latching has been implemented. The timing isnt completely accurate, but should be decent enough for now. Fixes Mars Check image test (corrupt lines from mode switching).
- Autofill timing has been implemented according to the docs. For now, this is just signaling via the FEN flag. Fixes MK II glitching et al.
2025-02-07 09:06:57 +00:00
Vincent Cunningham 04a51df859 ci: Update nightly tag to latest commit 2025-02-07 07:27:08 +00:00
Luke Usher 0c80c1e56b Merge remote-tracking branch 'origin/master' 2025-02-06 21:16:47 +00:00
Luke Usher 6f7618dc81 sh7604: log when wdt is used in watchdog mode 2025-02-06 21:16:29 +00:00
Luke Usher fdd7acb76b md: tweak 32X timing numbers
Should fix Brutal and Chaotix
2025-02-06 20:55:14 +00:00
Luke Usher 7ce2ffd010 md: tweak 32X timing numbers
Should fix Brutal and Chaotix
2025-02-06 20:54:38 +00:00
Vincent Cunningham bb22386f5f n64: Don't report interrupt exceptions to GDB
Interrupt exceptions fire multiple times per second and having to ack all of them can cause performance issues while debugging.
2025-02-06 19:04:36 +00:00
Luke Usher b372f65691 md: refactor sync between 32X components
Hopefully we don't see any negative impact from this;
I have tested many known timing-sensitive games with no ill effects locally.
2025-02-06 19:00:27 +00:00
Luke Usher 048d0e331d md: add internalStep function for 32x recompiler
Allows in-block calls to step() to become an increment which to be
actioned in bulk at the end of the recompiler block
2025-02-06 13:01:43 +00:00
jcm 1323a627b3 Update scripts and documentation 2025-02-06 06:41:02 +00:00
jcm b4ef96e4d6 Remove old macOS build script 2025-02-06 06:41:02 +00:00
jcm 8d2f88b745 build: Re-add librashader headers to source tree for Linux builds 2025-02-06 06:41:02 +00:00
jcm ca7eee17a9 build: Remove CMake platform definitions 2025-02-06 06:41:02 +00:00
jcm 9ef81df3cf build: Remove legacy gitignore entries 2025-02-06 06:41:02 +00:00
jcm 68af829f8e build: Remove legacy zconf header 2025-02-06 06:41:02 +00:00
jcm 56862e0026 build: Use configure_file to define version, copyright info 2025-02-06 06:41:02 +00:00
jcm 09d8af1c18 build: Rename configured files 2025-02-06 06:41:02 +00:00
jcm d20bc3c1b0 build: Remove legacy compatibility compile definitions 2025-02-06 06:41:02 +00:00
jcm 97c82119b5 build: Remove resource files 2025-02-06 06:41:02 +00:00
jcm b78228c5c0 build: Remove legacy workflow 2025-02-06 06:41:02 +00:00
jcm 5107ed00cb build: Remove dynamic dependencies from thirdparty 2025-02-06 06:41:02 +00:00
jcm aeff8ec8f9 build: Remove GNUmakefiles 2025-02-06 06:41:02 +00:00
Christopher Bonhage 7640e1598c n64: fix Joybus RTC read/write status byte (#1814)
As documented in the N64brew wiki:
https://n64brew.dev/wiki/Joybus_Protocol#0x07_-_Read_Real-Time_Clock_Block

The final output byte of Joybus RTC read/write commands should be the
RTC status.

This intended behavior has been confirmed with Mateusz Faderewski, the
creator of SummerCart.
2025-02-05 23:58:05 +01:00
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
4883 changed files with 79188 additions and 547459 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
+2
View File
@@ -0,0 +1,2 @@
# When archiving, export a version file containing tag/commit information
cmake/common/.archive-version.json export-subst
+26
View File
@@ -0,0 +1,26 @@
#!/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" \
-parallelizeTargets \
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 ] || [ "$ARES_PLATFORM_NAME" = "windows-arm64" ]; 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
+44
View File
@@ -0,0 +1,44 @@
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 -y ../ares-${package}.zip ${outdir}
zip -r -y ../ares-${package}-dSYMs.zip ${outdir}-dSYMs
cd -
done
for package in windows-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
+112
View File
@@ -0,0 +1,112 @@
name: Build (Auxiliary)
on:
workflow_call
jobs:
build:
strategy:
fail-fast: false
matrix:
program:
- ares
config:
- RelWithDebInfo
platform:
- name: windows-x64-gcc
os: windows-latest
shell: 'msys2 {0}'
msystem: mingw64
install: make git cmake ccache ninja 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-arm64
os: windows-11-arm
compiler: clang++
shell: 'msys2 {0}'
msystem: clangarm64
install: mingw-w64-clang-aarch64-make git mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ccache mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-clang
target-cmake-preset: windows-ci-mingw-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: ubuntu-gcc-x64
os: ubuntu-24.04
shell: bash
target-cmake-preset: ubuntu-ci
- name: ubuntu-gcc-arm64
os: ubuntu-24.04-arm
shell: bash
target-cmake-preset: ubuntu-ci
- name: ubuntu-clang-x64
os: ubuntu-24.04
shell: bash
target-cmake-preset: ubuntu-ci-clang
- name: ubuntu-clang-arm64
os: ubuntu-24.04-arm
shell: bash
target-cmake-preset: ubuntu-ci-clang
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@40677d36a502eb2cf0fb808cc9dec31bf6152638
with:
msystem: ${{ matrix.platform.msystem }}
install: ${{ matrix.platform.install }}
- name: Checkout source code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-tags: true
fetch-depth: 0
- name: Setup MSYS2 Git Environment
if: matrix.platform.shell == 'msys2 {0}'
run: |
git config core.autocrlf true
- name: Install Linux Dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update -y -qq
sudo apt-get install cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
- 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:
ARES_PLATFORM_NAME: ${{ matrix.platform.name }}
CROSS_COMPILE: ${{ matrix.platform.native-cmake-preset != '' }}
NATIVE_PRESET: ${{ matrix.platform.native-cmake-preset }}
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
- name: "Compress Build Artifacts (Windows)"
if: runner.os != 'macOS' && runner.os != 'Linux'
run: |
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/rundir/ .
- name: Upload Build
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}
path: ares-${{ matrix.platform.name }}.tar.xz
- name: Upload Debug Symbols (Windows)
if: runner.os != 'macOS' && runner.os != 'Linux'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
path: build/PDBs/*
+83 -285
View File
@@ -1,10 +1,17 @@
name: Build
name: Build (Primary)
on:
push:
branches: [ master ]
tags: [ 'v*' ]
pull_request:
branches: [ master ]
workflow_call:
inputs:
codesign:
description: Enable codesigning
required: false
default: false
type: boolean
official:
description: Use official version strings
required: true
default: true
type: boolean
jobs:
build:
strategy:
@@ -12,57 +19,28 @@ jobs:
matrix:
program:
- ares
config:
- RelWithDebInfo
platform:
- name: windows
- name: windows-x64
os: windows-latest
compiler: clang++
windres: windres
shell: 'msys2 {0}'
msystem: clang64
install: mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-pkgconf mingw-w64-clang-x86_64-SDL2
- name: windows-arm64
install: make git cmake ccache ninja mingw-w64-clang-x86_64-clang
target-cmake-preset: windows-ci-mingw-native
- name: windows-clang-cl-arm64
os: windows-latest
compiler: clang++ --target=aarch64-w64-windows-gnu --sysroot=/clangarm64 -resource-dir=/clangarm64/lib/clang/$(basename "$(clang++ -print-resource-dir)")
windres: windres --target=aarch64-w64-windows-gnu
shell: 'msys2 {0}'
msystem: clang64
install: mingw-w64-clang-x86_64-clang mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-pkgconf mingw-w64-clang-aarch64-SDL2
- name: windows-msvc-x64
os: windows-latest
compiler: clang++
windres: llvm-rc
shell: bash
msvc-arch: x64
- name: windows-msvc-arm64
os: windows-latest
compiler: clang++ --target=aarch64-w64-windows-msvc
windres: llvm-rc
shell: bash
msvc-arch: x64_arm64
- name: windows-cl-x64
os: windows-latest
compiler: cl
windres: rc
shell: bash
msvc-arch: x64
- name: windows-cl-arm64
os: windows-latest
compiler: cl
windres: rc
shell: bash
msvc-arch: x64_arm64
- name: macos-compat
os: macos-12
target-cmake-preset: windows-ci-cl-cross
native-cmake-preset: windows-ci-cl-native
- name: macos-universal
os: macos-15
compiler: clang++
shell: sh
- name: macos-latest
os: macos-latest
compiler: clang++
shell: sh
- name: ubuntu
os: ubuntu-latest
compiler: g++
shell: sh
install: cmake ccache xcbeautify
target-cmake-preset: macos-ci-universal
name: ${{ matrix.program }}-${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
defaults:
@@ -71,264 +49,84 @@ jobs:
steps:
- name: Install MSYS2 Dependencies
if: matrix.platform.shell == 'msys2 {0}'
uses: msys2/setup-msys2@v2
uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638
with:
msystem: ${{ matrix.platform.msystem }}
install: make ${{ matrix.platform.install }}
install: ${{ matrix.platform.install }}
- name: "macOS: Import Certificate"
if: runner.os == 'macOS' && inputs.codesign
uses: apple-actions/import-codesign-certs@65cfbc37e1464d733524cb555b724878f278b8c3
continue-on-error: ${{ secrets.MACOS_CERTIFICATE_NAME == '' }}
with:
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_DATA }}
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
- name: Checkout source code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-tags: true
fetch-depth: 0
- name: Setup MSYS2 Git Environment
if: matrix.platform.shell == 'msys2 {0}'
run: |
git config core.autocrlf true
- name: Install Linux Dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update -y -qq
sudo apt-get install libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
- name: "macOS: Import Certificate"
if: runner.os == 'macOS' && github.event_name != 'pull_request'
continue-on-error: ${{ github.repository != 'ares-emulator/ares' }}
uses: wpilibsuite/import-signing-certificate@2ac4f44d28045073d23153256efbb4c4b2d8aa22 # Don't use rolling branch for security reasons
with:
certificate-data: ${{ secrets.MACOS_CERTIFICATE_DATA }}
certificate-passphrase: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
keychain-name: ares-macos-keychain
keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
- name: Checkout source code
uses: actions/checkout@v4
- name: Install Windows Dependencies
if: runner.os == 'Windows'
run: |
export PATH="/c/Users/runneradmin/.cargo/bin:$PATH" # correct on windows-latest as of 2024-02-19
if [[ ${{ matrix.platform.name }} == *-arm64 ]]; then
rustup toolchain install nightly
rustup default nightly
rustup target add aarch64-pc-windows-msvc
pushd thirdparty/librashader
./build-librashader.sh aarch64-pc-windows-msvc
popd
else
rustup toolchain install nightly
rustup default nightly
pushd thirdparty/librashader
./build-librashader.sh
popd
fi
- name: "macOS: recover MoltenVK cache"
if: runner.os == 'macOS'
uses: actions/cache@v4
env:
cache-name: moltenvk
with:
path: thirdparty/MoltenVK/MoltenVK
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('thirdparty/MoltenVK/HEAD') }}
sudo apt-get install ${{ matrix.platform.install }}
- name: Install macOS Dependencies
if: runner.os == 'macOS'
run: |
if [ $ImageOS == "macos14" ]; then
sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
export MACOSX_DEPLOYMENT_TARGET=10.13
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
export MACOSX_DEPLOYMENT_TARGET=10.9
echo "Set Xcode version to 13.4 for macos-compat build."
fi
brew install make 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
- name: Set up MSVC environment
if: matrix.platform.msvc-arch != ''
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.platform.msvc-arch }}
- name: Make
if: runner.os != 'macOS'
run: ${MAKE:-make} -j4 -C desktop-ui build=optimized local=false compiler="${{ matrix.platform.compiler }}" windres="${{ matrix.platform.windres }}"
- name: "macOS: Make universal app"
if: runner.os == 'macOS'
run: scripts/macos-make-universal.sh build=optimized local=false
brew install ${{ matrix.platform.install }}
- name: "Build: Windows"
if: runner.os != 'macOS' && runner.os != 'Linux'
run: .github/scripts/build_windows.sh
env:
MAKEFLAGS: -j3
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
MACOS_KEYCHAIN_NAME: ares-macos-keychain
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
ARES_BUILD_OFFICIAL: ${{ inputs.official }}
ARES_PLATFORM_NAME: ${{ matrix.platform.name }}
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' && github.event_name != 'pull_request'
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: 'desktop-ui/out'
timestampUrl: 'http://timestamp.digicert.com'
- name: "macOS: notarize"
if: runner.os == 'macOS' && github.event_name != 'pull_request'
continue-on-error: ${{ github.repository != 'ares-emulator/ares' }}
run: |
ditto -c -k --keepParent desktop-ui/out/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 desktop-ui/out/ares.app
folder: 'build/desktop-ui/rundir/'
timestampUrl: 'http://timestamp.digicert.com'
- name: "Build: macOS"
if: runner.os == 'macOS'
run: .github/scripts/build_macos.sh
env:
MACOS_NOTARIZATION_USERNAME: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
MACOS_NOTARIZATION_PASSWORD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
ARES_BUILD_OFFICIAL: ${{ inputs.official }}
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
- name: Upload
uses: actions/upload-artifact@v4
- name: "Compress Build Artifact (macOS)"
if: runner.os == 'macOS'
run: |
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/RelWithDebInfo/ .
- name: "Compress Build Artifacts (Windows)"
if: runner.os != 'macOS' && runner.os != 'Linux'
run: |
tar -cvJf ares-${{ matrix.platform.name }}.tar.xz -C build/desktop-ui/rundir/ .
- name: Upload Build
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}
path: desktop-ui/out/*
release:
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
needs:
- build
steps:
- uses: actions/checkout@v4
path: ares-${{ matrix.platform.name }}.tar.xz
- name: Upload Debug Symbols (Windows)
if: runner.os != 'macOS' && runner.os != 'Linux'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
path: 'src'
- name: Download Artifacts
uses: actions/download-artifact@v4
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
path: build/PDBs/*
- name: Upload Debug Symbols (macOS)
if: runner.os == 'macOS'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
path: 'bin'
- name: Package Artifacts
run: |
set -eu
case ${GITHUB_REF} in
refs/tags/*) suffix="-${GITHUB_REF#refs/tags/}" ;;
refs/heads/master) suffix="-nightly" ;;
*) suffix="" ;;
esac
srcdir="${GITHUB_WORKSPACE}/src"
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
for package in windows windows-msvc-arm64 macos-latest macos-compat
do
mkdir "${package}"
cd "${package}"
# Package ares.
outdir=ares${suffix}
mkdir ${outdir}
cp -ar ${bindir}/ares-${package}/* ${outdir}
zip -r ../ares-${package}.zip ${outdir}
cd -
done
- name: Create Release
id: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -eu
github_rest()
{
local method="${1}"
local url="https://api.github.com${2}"
shift 2
>&2 echo "${method} ${url}"
curl \
--fail \
-H "Accept: application/vnd.github.v3+json" \
-H "Authorization: token ${GITHUB_TOKEN}" \
-X "${method}" \
"${url}" \
"$@"
}
github_get_release_id_for_tag()
{
payload=$(github_rest GET "/repos/${GITHUB_REPOSITORY}/releases/tags/${1}") || return
echo "${payload}" | jq .id
}
github_delete_release_by_id()
{
github_rest DELETE "/repos/${GITHUB_REPOSITORY}/releases/${1}"
}
github_create_release()
{
local payload="{
\"tag_name\": \"${1}\",
\"target_commitish\": \"${2}\",
\"name\": \"${3}\",
\"body\": \"${4}\",
\"draft\": ${5},
\"prerelease\": ${6}
}"
github_rest POST "/repos/${GITHUB_REPOSITORY}/releases" -d "${payload}"
}
make_nightly_release()
{
github_create_release \
nightly \
"${GITHUB_SHA}" \
"ares nightly $(date +"%Y-%m-%d")" \
"Auto-generated nightly release on $(date -u +"%Y-%m-%d %T %Z")" \
false \
true
}
make_version_release()
{
github_create_release \
"${1}" \
"${GITHUB_SHA}" \
"ares ${1}" \
"This is ares ${1}, released on $(date +"%Y-%m-%d")." \
false \
false
}
case ${GITHUB_REF} in
refs/tags/*)
# Create a new version release using the current revision.
echo "UPLOAD_URL=$(make_version_release ${GITHUB_REF#refs/tags/} | jq -r .upload_url)" >> $GITHUB_ENV
;;
refs/heads/master)
# Check for an existing nightly release.
{ release_id=$(github_get_release_id_for_tag nightly); status=$?; } || true
# Delete existing nightly release if it exists.
case ${status} in
0) github_delete_release_by_id "${release_id}" ;;
22) >&2 echo "No current nightly release; skipping tag deletion." ;;
*) >&2 echo "API call failed unexpectedly." && exit 1 ;;
esac
# Create a new nightly release using the current revision.
echo "UPLOAD_URL=$(make_nightly_release | jq -r .upload_url)" >> $GITHUB_ENV
;;
esac
- name: Upload ares-windows
uses: actions/upload-release-asset@v1
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows.zip', asset_name: 'ares-windows.zip', asset_content_type: 'application/zip' }
- 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
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' }
# - 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' }
name: ${{ matrix.program }}-${{ matrix.platform.name }}-dSYMs
path: build/dSYMs/*
+23
View File
@@ -0,0 +1,23 @@
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 ares (primary)
uses: ./.github/workflows/build.yml
permissions:
contents: read
with:
official: false
build-aux:
name: Build ares (auxiliary)
uses: ./.github/workflows/build-aux.yml
secrets: inherit
+27
View File
@@ -0,0 +1,27 @@
name: Push
on:
push
concurrency:
group: '${{ github.workflow }} @ ${{ github.head_ref || github.ref }}'
cancel-in-progress: true
permissions:
contents: write
jobs:
build:
name: Build ares (primary)
uses: ./.github/workflows/build.yml
secrets: inherit
with:
codesign: true
official: ${{ github.ref_name == 'master' || github.ref_type == 'tag' }}
build-aux:
name: Build ares (auxiliary)
uses: ./.github/workflows/build-aux.yml
secrets: inherit
release:
name: Release
needs: build
secrets: inherit
uses: ./.github/workflows/release.yml
with:
notarize: true
+81
View File
@@ -0,0 +1,81 @@
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@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: 'src'
- name: Download Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
path: 'bin'
- name: "Decompress Build Artifacts"
if: runner.os == 'macOS'
run: |
for package in macos-universal windows-x64 windows-clang-cl-arm64; do
pushd bin/ares-${package}
tar -xJf ares-${package}.tar.xz
rm -f ares-${package}.tar.xz
popd
done
- 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: Update Git Tag
if: steps.check.outputs.tag == 'nightly'
id: update-tag
run: |
git -C src tag -f ${{ steps.check.outputs.tag }}
git -C src push -f origin ${{ steps.check.outputs.tag }}
- name: Create Release 🛫
id: create_release
uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191
with:
prerelease: ${{ steps.check.outputs.tag == 'nightly' }}
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-arm64.zip
${{ github.workspace }}/ares-windows-clang-cl-arm64-PDBs.zip
+50 -18
View File
@@ -1,18 +1,50 @@
*.moc
*.user
*.xcuserdata
.vs/
.vscode/
.idea/
cmake-*/
obj/
out/
obj-amd64/
obj-arm64/
out-amd64/
out-arm64/
thirdparty/SDL/SDL
thirdparty/SDL/libSDL2-2.0.0.dylib
macos-xcode/
.swiftpm
*.xcodeproj
# 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
# Exclude old macOS Finder metadata
.DS_Store
# Exclude generated sources that still reside in-tree
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
mia/resource/resource.cpp
mia/resource/resource.hpp
# Exclude fetched third-party processor test binaries
tests/arm7tdmi/tests
tests/m68000/tests
# Exclude unused legacy zlib header that is renamed by CMake
thirdparty/libchdr/deps/zlib-*/zconf.h
thirdparty/libchdr/deps/zlib-*/zconf.h.included
+55
View File
@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.28...4.0)
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/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()
+187
View File
@@ -0,0 +1,187 @@
{
"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,
"ARES_BUILD_OFFICIAL": {"type": "BOOL", "value": "$penv{ARES_BUILD_OFFICIAL}"}
}
},
{
"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.15"},
"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
}
},
{
"name": "ubuntu-ci-clang",
"displayName": "Ubuntu CI (clang)",
"description": "Single-arch binary for building on Github Actions",
"inherits": ["ubuntu-ci"],
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++"
}
}
],
"buildPresets": [
{
"name": "windows",
"configurePreset": "windows",
"displayName": "Windows build (host architecture)",
"description": "Windows build (host architecture)",
"configuration": "RelWithDebInfo"
}
]
}
-6
View File
@@ -1,6 +0,0 @@
targets = all clean install uninstall verbose
$(targets):
@$(MAKE) -C desktop-ui $@
.PHONY: $(targets)
+1 -1
View File
@@ -1,7 +1,7 @@
----------------------------------------------------------------------
ares
Copyright (c) 2004-2021 ares team, Near et al
Copyright (c) 2004-2025 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
+11 -121
View File
@@ -1,10 +1,12 @@
![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)
**ares** is a multi-system emulator that began development on October 14th, 2004.
It is a descendant of [higan](https://github.com/higan-emu/higan) and [bsnes](https://github.com/bsnes-emu/bsnes/), and focuses on accuracy and preservation.
It's worth noting that ares takes some uncommon design approaches that essentially trade speed for code clarity. We avoid state machines and bitmasks (when possible). Most cores end up being half the amount of code, but slower. The code is clearer and less spaghettified, especially for systems with lots of processors. C bitfields being non-portable incurs a speedhit. Windows also has a speedhit over Linux due to its ABI needing more instructions to switch contexts.
Official Releases
-----------------
@@ -14,130 +16,18 @@ Official releases are available from
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).
Automated, untested builds of ares are available for Windows and macOS as a [pre-release](https://github.com/ares-emulator/ares/releases/tag/nightly).
Only the latest nightly build is kept.
Prerequisites
Building ares
-------------
### *nix building
###### 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/*`
ares supports building on Windows, macOS, and various Linux/BSD distributions. See build instructions for:
* [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)
Command-line options
--------------------
@@ -150,7 +40,7 @@ Usage: ./ares [options] game(s)
--help Displays available options and exit
--fullscreen Start in full screen mode
--system system Specify the system name
--shader shader Specify GLSL shader name to load (requires OpenGL driver)
--shader shader Specify a slang shader to load (requires OpenGL or Metal)
--setting name=value Specify a value for a setting
--dump-all-settings Show a list of all existing settings and exit
--no-file-prompt Do not prompt to load (optional) additional roms (eg: 64DD)
+314
View File
@@ -0,0 +1,314 @@
add_library(ares STATIC ares/ares.cpp ares/memory/fixed-allocator.cpp)
configure_file(ares/ares.cpp.in ares/ares.cpp @ONLY)
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.cpp.in 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
n64/vulkan/parallel-rdp/vulkan/context.cpp
n64/vulkan/parallel-rdp/vulkan/memory_allocator.cpp
n64/vulkan/parallel-rdp/vulkan/semaphore.cpp
n64/vulkan/parallel-rdp/util/logging.cpp
n64/vulkan/parallel-rdp/util/environment.cpp
n64/vulkan/parallel-rdp/util/thread_name.cpp
n64/vulkan/parallel-rdp/util/timer.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})
-108
View File
@@ -1,108 +0,0 @@
ifeq ($(platform),windows)
options += $(call lib,uuid kernel32 user32 gdi32 comctl32 comdlg32 shell32)
else ifeq ($(platform),macos)
else ifneq ($(filter $(platform),linux bsd),)
options += -Wl,-export-dynamic
options += -lX11 -lXext
else
$(error "ares is a library and cannot be built directly.")
endif
ares.objects := ares ares-fixed-allocator
$(object.path)/ares.o: $(ares.path)/ares/ares.cpp
$(object.path)/ares-fixed-allocator.o: $(ares.path)/ares/memory/fixed-allocator.cpp
ifeq ($(vulkan),true)
flags += -DVULKAN
endif
ifeq ($(profile),accuracy)
flags += -DPROFILE_ACCURACY
endif
ifeq ($(profile),performance)
flags += -DPROFILE_PERFORMANCE
endif
ifneq ($(filter $(cores),a26),)
include $(ares.path)/a26/GNUmakefile
endif
ifneq ($(filter $(cores),fc),)
include $(ares.path)/fc/GNUmakefile
endif
ifneq ($(filter $(cores),sfc),)
include $(ares.path)/sfc/GNUmakefile
endif
ifneq ($(filter $(cores),n64),)
include $(ares.path)/n64/GNUmakefile
endif
ifneq ($(filter $(cores),sg),)
include $(ares.path)/sg/GNUmakefile
endif
ifneq ($(filter $(cores),ms),)
include $(ares.path)/ms/GNUmakefile
endif
ifneq ($(filter $(cores),md),)
include $(ares.path)/md/GNUmakefile
endif
ifneq ($(filter $(cores),saturn),)
include $(ares.path)/saturn/GNUmakefile
endif
ifneq ($(filter $(cores),ps1),)
include $(ares.path)/ps1/GNUmakefile
endif
ifneq ($(filter $(cores),pce),)
include $(ares.path)/pce/GNUmakefile
endif
ifneq ($(filter $(cores),msx),)
include $(ares.path)/msx/GNUmakefile
endif
ifneq ($(filter $(cores),cv),)
include $(ares.path)/cv/GNUmakefile
endif
ifneq ($(filter $(cores),myvision),)
include $(ares.path)/myvision/GNUmakefile
endif
ifneq ($(filter $(cores),gb),)
include $(ares.path)/gb/GNUmakefile
endif
ifneq ($(filter $(cores),gba),)
include $(ares.path)/gba/GNUmakefile
endif
ifneq ($(filter $(cores),ws),)
include $(ares.path)/ws/GNUmakefile
endif
ifneq ($(filter $(cores),ng),)
include $(ares.path)/ng/GNUmakefile
endif
ifneq ($(filter $(cores),ngp),)
include $(ares.path)/ngp/GNUmakefile
endif
ifneq ($(filter $(cores),spec),)
include $(ares.path)/spec/GNUmakefile
endif
include $(ares.path)/component/GNUmakefile
flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c)
ares.objects := $(ares.objects:%=$(object.path)/%.o)
+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
)
-15
View File
@@ -1,15 +0,0 @@
ares.components += mos6502
ares.objects += ares-a26-system
ares.objects += ares-a26-controller
ares.objects += ares-a26-cartridge
ares.objects += ares-a26-cpu
ares.objects += ares-a26-tia
ares.objects += ares-a26-riot
$(object.path)/ares-a26-system.o: $(ares.path)/a26/system/system.cpp
$(object.path)/ares-a26-controller.o: $(ares.path)/a26/controller/controller.cpp
$(object.path)/ares-a26-cartridge.o: $(ares.path)/a26/cartridge/cartridge.cpp
$(object.path)/ares-a26-cpu.o: $(ares.path)/a26/cpu/cpu.cpp
$(object.path)/ares-a26-tia.o: $(ares.path)/a26/tia/tia.cpp
$(object.path)/ares-a26-riot.o: $(ares.path)/a26/riot/riot.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
View File
@@ -54,6 +54,7 @@ auto System::load(Node::System& root, string name) -> bool {
}
node = Node::System::create(information.name);
node->setAttribute("configuration", name);
node->setGame({&System::game, this});
node->setRun({&System::run, this});
node->setPower({&System::power, this});
+6 -6
View File
@@ -7,15 +7,15 @@
namespace ares {
Platform* platform = nullptr;
bool _runAhead = false;
atomic<bool> _runAhead = false;
const string Name = "ares";
const string Version = "141";
const string Copyright = "ares team, Near";
const string Name = "@ARES_NAME@";
const string Version = "@ARES_VERSION@";
const string Copyright = "@ARES_LEGAL_COPYRIGHT_SHORT@";
const string License = "ISC";
const string LicenseURI = "https://opensource.org/licenses/ISC";
const string Website = "ares-emu.net";
const string WebsiteURI = "https://ares-emu.net/";
const string Website = "@ARES_WEBSITE@";
const string WebsiteURI = "https://@ARES_WEBSITE@/";
const u32 SerializerSignature = 0x31545342; //"BST1" (little-endian)
}
+14 -2
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>
@@ -65,11 +66,23 @@ namespace ares {
}
}
extern bool _runAhead;
extern atomic<bool> _runAhead;
inline auto runAhead() -> bool { return _runAhead; }
inline auto setRunAhead(bool runAhead) -> void { _runAhead = runAhead; }
}
/// ares elects to use the reserved C++ `register` identifier liberally in a few different areas so that it can more
/// freely describe hardware registers within emulated system components. This macro exists to prevent compilers
/// exploding at the sight of the reserved identifier.
///
/// Perhaps unsurprisingly, this macro will conflict with certain system headers. MSVC headers will emit an error
/// forbidding macroizing `register` if the identifier is defined, while the `clangarm64` system headers in MSYS2
/// appear to try to make use of the obsolete keyword meaning of the identifier.
///
/// Defining this macro after all platform headers are included avoids these conflicts... for now. Removing this
/// macro along with all uses of this identifier may inevitably become necessary in the future.
#define register $register
#include <ares/types.hpp>
#include <ares/random.hpp>
#include <ares/debug/debug.hpp>
@@ -78,4 +91,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
View File
@@ -24,6 +24,7 @@ Screen::~Screen() {
}
auto Screen::main(uintptr_t) -> void {
thread::setName("dev.ares.screen");
while(!_kill) {
unique_lock<mutex> lock(_frameMutex);
+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)
-10
View File
@@ -1,10 +0,0 @@
build := stable
nall.path := ../../../nall
include $(nall.path)/GNUmakefile
all:
sourcery resource.bml resource.cpp resource.hpp
clean:
$(call delete,resource.cpp)
$(call delete,resource.hpp)
File diff suppressed because it is too large. Load diff
-34
View File
@@ -1,34 +0,0 @@
namespace Resource {
namespace Ares {
extern const unsigned char Icon1x[6562];
extern const unsigned char Icon2x[9662];
extern const unsigned char Logo1x[11533];
extern const unsigned char Logo2x[18991];
}
namespace Sprite {
namespace SuperFamicom {
extern const unsigned char CrosshairBlue[332];
extern const unsigned char CrosshairGreen[329];
extern const unsigned char CrosshairRed[342];
}
namespace WonderSwan {
extern const unsigned char Auxiliary0[117];
extern const unsigned char Auxiliary1[134];
extern const unsigned char Auxiliary2[136];
extern const unsigned char Headphones[167];
extern const unsigned char Initialized[136];
extern const unsigned char LowBattery[144];
extern const unsigned char Orientation0[148];
extern const unsigned char Orientation1[150];
extern const unsigned char PoweredOn[155];
extern const unsigned char Sleeping[154];
extern const unsigned char VolumeA0[129];
extern const unsigned char VolumeA1[142];
extern const unsigned char VolumeA2[146];
extern const unsigned char VolumeB0[125];
extern const unsigned char VolumeB1[137];
extern const unsigned char VolumeB2[148];
extern const unsigned char VolumeB3[153];
}
}
}
+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)
+481
View File
@@ -0,0 +1,481 @@
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
s3511a
PRIMARY
rtc/s3511a/s3511a.cpp
INCLUDED
rtc/s3511a/s3511a.hpp
rtc/s3511a/serialization.cpp
)
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
)
-76
View File
@@ -1,76 +0,0 @@
ares.components := $(call unique,$(ares.components))
ares.objects += $(if $(findstring ay38910,$(ares.components)),ares-audio-ay38910)
ares.objects += $(if $(findstring msm5205,$(ares.components)),ares-audio-msm5205)
ares.objects += $(if $(findstring sn76489,$(ares.components)),ares-audio-sn76489)
ares.objects += $(if $(findstring t6w28,$(ares.components)),ares-audio-t6w28)
ares.objects += $(if $(findstring ym2149,$(ares.components)),ares-audio-ym2149)
ares.objects += $(if $(findstring ym2413,$(ares.components)),ares-audio-ym2413)
ares.objects += $(if $(findstring ym2610,$(ares.components)),ares-audio-ym2610)
ares.objects += $(if $(findstring ym2612,$(ares.components)),ares-audio-ym2612)
ares.objects += $(if $(findstring m24c,$(ares.components)),ares-eeprom-m24c)
ares.objects += $(if $(findstring m93lcx6,$(ares.components)),ares-eeprom-m93lcx6)
ares.objects += $(if $(findstring i8255,$(ares.components)),ares-io-i8255)
ares.objects += $(if $(findstring arm7tdmi,$(ares.components)),ares-processor-arm7tdmi)
ares.objects += $(if $(findstring gsu,$(ares.components)),ares-processor-gsu)
ares.objects += $(if $(findstring hg51b,$(ares.components)),ares-processor-hg51b)
ares.objects += $(if $(findstring huc6280,$(ares.components)),ares-processor-huc6280)
ares.objects += $(if $(findstring i8080,$(ares.components)),ares-processor-i8080)
ares.objects += $(if $(findstring m68hc05,$(ares.components)),ares-processor-m68hc05)
ares.objects += $(if $(findstring m68000,$(ares.components)),ares-processor-m68000)
ares.objects += $(if $(findstring mos6502,$(ares.components)),ares-processor-mos6502)
ares.objects += $(if $(findstring sh2,$(ares.components)),ares-processor-sh2)
ares.objects += $(if $(findstring sm5k,$(ares.components)),ares-processor-sm5k)
ares.objects += $(if $(findstring sm83,$(ares.components)),ares-processor-sm83)
ares.objects += $(if $(findstring spc700,$(ares.components)),ares-processor-spc700)
ares.objects += $(if $(findstring ssp1601,$(ares.components)),ares-processor-ssp1601)
ares.objects += $(if $(findstring tlcs900h,$(ares.components)),ares-processor-tlcs900h)
ares.objects += $(if $(findstring upd96050,$(ares.components)),ares-processor-upd96050)
ares.objects += $(if $(findstring v30mz,$(ares.components)),ares-processor-v30mz)
ares.objects += $(if $(findstring wdc65816,$(ares.components)),ares-processor-wdc65816)
ares.objects += $(if $(findstring z80,$(ares.components)),ares-processor-z80)
ares.objects += $(if $(findstring sst39sf0x0,$(ares.components)),ares-flash-sst39sf0x0)
ares.objects += $(if $(findstring tms9918,$(ares.components)),ares-video-tms9918)
ares.objects += $(if $(findstring v9938,$(ares.components)),ares-video-v9938)
$(object.path)/ares-audio-ay38910.o: $(ares.path)/component/audio/ay38910/ay38910.cpp
$(object.path)/ares-audio-msm5205.o: $(ares.path)/component/audio/msm5205/msm5205.cpp
$(object.path)/ares-audio-sn76489.o: $(ares.path)/component/audio/sn76489/sn76489.cpp
$(object.path)/ares-audio-t6w28.o: $(ares.path)/component/audio/t6w28/t6w28.cpp
$(object.path)/ares-audio-ym2149.o: $(ares.path)/component/audio/ym2149/ym2149.cpp
$(object.path)/ares-audio-ym2413.o: $(ares.path)/component/audio/ym2413/ym2413.cpp
$(object.path)/ares-audio-ym2612.o: $(ares.path)/component/audio/ym2612/ym2612.cpp
$(object.path)/ares-eeprom-m24c.o: $(ares.path)/component/eeprom/m24c/m24c.cpp
$(object.path)/ares-eeprom-m93lcx6.o: $(ares.path)/component/eeprom/m93lcx6/m93lcx6.cpp
$(object.path)/ares-io-i8255.o: $(ares.path)/component/io/i8255/i8255.cpp
$(object.path)/ares-processor-arm7tdmi.o: $(ares.path)/component/processor/arm7tdmi/arm7tdmi.cpp
$(object.path)/ares-processor-gsu.o: $(ares.path)/component/processor/gsu/gsu.cpp
$(object.path)/ares-processor-hg51b.o: $(ares.path)/component/processor/hg51b/hg51b.cpp
$(object.path)/ares-processor-huc6280.o: $(ares.path)/component/processor/huc6280/huc6280.cpp
$(object.path)/ares-processor-i8080.o: $(ares.path)/component/processor/i8080/i8080.cpp
$(object.path)/ares-processor-m68hc05.o: $(ares.path)/component/processor/m68hc05/m68hc05.cpp
$(object.path)/ares-processor-m68000.o: $(ares.path)/component/processor/m68000/m68000.cpp
$(object.path)/ares-processor-mos6502.o: $(ares.path)/component/processor/mos6502/mos6502.cpp
$(object.path)/ares-processor-sh2.o: $(ares.path)/component/processor/sh2/sh2.cpp
$(object.path)/ares-processor-sm5k.o: $(ares.path)/component/processor/sm5k/sm5k.cpp
$(object.path)/ares-processor-sm83.o: $(ares.path)/component/processor/sm83/sm83.cpp
$(object.path)/ares-processor-spc700.o: $(ares.path)/component/processor/spc700/spc700.cpp
$(object.path)/ares-processor-ssp1601.o: $(ares.path)/component/processor/ssp1601/ssp1601.cpp
$(object.path)/ares-processor-tlcs900h.o: $(ares.path)/component/processor/tlcs900h/tlcs900h.cpp
$(object.path)/ares-processor-upd96050.o: $(ares.path)/component/processor/upd96050/upd96050.cpp
$(object.path)/ares-processor-v30mz.o: $(ares.path)/component/processor/v30mz/v30mz.cpp
$(object.path)/ares-processor-wdc65816.o: $(ares.path)/component/processor/wdc65816/wdc65816.cpp
$(object.path)/ares-processor-z80.o: $(ares.path)/component/processor/z80/z80.cpp
$(object.path)/ares-flash-sst39sf0x0.o: $(ares.path)/component/flash/sst39sf0x0/sst39sf0x0.cpp
$(object.path)/ares-video-tms9918.o: $(ares.path)/component/video/tms9918/tms9918.cpp
$(object.path)/ares-video-v9938.o: $(ares.path)/component/video/v9938/v9938.cpp
+23 -23
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);
@@ -126,12 +125,12 @@ auto YM2612::Channel::Operator::updatePhase() -> void {
auto YM2612::Channel::Operator::updateLevel() -> void {
u32 lfo = ym2612.lfo.clock & 0x40 ? ym2612.lfo.clock & 0x3f : ~ym2612.lfo.clock & 0x3f;
u32 depth = tremolos[channel.tremolo];
u32 depth = tremolos[tremoloEnable * channel.tremolo];
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 {
@@ -148,7 +147,8 @@ auto YM2612::Channel::power() -> void {
for(auto& op : operators) {
op.keyOn = 0;
op.keyLine = 0;
op.lfoEnable = 0;
op.tremoloEnable = 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;
+11 -13
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;
}
@@ -34,18 +36,14 @@ auto YM2612::writeData(n8 data) -> void {
//timer B period
case 0x026: {
timerB.period.bit(0,7) = data.bit(0,7);
// Not sure if this is the right place for it, but...
// handle a specific use case to reset the subticks on timer B
if(!timerB.enable) timerB.divider = 0;
break;
}
//timer control
case 0x027: {
//reload period on 0->1 transition
if(!timerA.enable && data.bit(0)) timerA.counter = timerA.period;
if(!timerB.enable && data.bit(1)) {
timerB.counter = timerB.period;
timerB.divider = 0;
}
timerA.enable = data.bit(0);
timerB.enable = data.bit(1);
timerA.irq = data.bit(2);
@@ -114,19 +112,19 @@ 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;
}
//LFO enable, decay rate
//LFO AM enable, decay rate
case 0x060: {
op.envelope.decayRate = data.bit(0,4);
op.lfoEnable = data.bit(7);
op.tremoloEnable = data.bit(7);
channel[index].updateEnvelope();
channel[index].updateLevel();
break;
@@ -13,12 +13,14 @@ auto YM2612::serialize(serializer& s) -> void {
s(envelope.divider);
s(timerA.enable);
s(timerA.enableLatch);
s(timerA.irq);
s(timerA.line);
s(timerA.period);
s(timerA.counter);
s(timerB.enable);
s(timerB.enableLatch);
s(timerB.irq);
s(timerB.line);
s(timerB.period);
@@ -43,7 +45,8 @@ auto YM2612::Channel::serialize(serializer& s) -> void {
auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
s(keyOn);
s(keyLine);
s(lfoEnable);
s(tremoloEnable);
s(keyScale);
s(detune);
s(multiple);
s(totalLevel);
@@ -68,7 +71,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);
+10 -11
View File
@@ -1,16 +1,15 @@
auto YM2612::TimerA::run() -> void {
if(!enable) return;
if(++counter) return;
counter = period;
line |= irq;
if(!++counter)
line |= irq & enableLatch;
if(enableLatch < enable || !counter)
counter = period;
enableLatch = enable;
}
auto YM2612::TimerB::run() -> void {
if(!enable) return;
if(++divider) return;
if(++counter) return;
counter = period;
line |= irq;
if(!++divider && !++counter)
line |= irq & enableLatch;
if(enableLatch < enable || !counter && !divider)
counter = period; // do not reset divider on reenable
enableLatch = enable;
}
+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)};
}
+5 -2
View File
@@ -45,6 +45,7 @@ protected:
auto run() -> void;
n1 enable = 0;
n1 enableLatch = 0;
n1 irq = 0;
n1 line = 0;
n10 period = 0;
@@ -56,6 +57,7 @@ protected:
auto run() -> void;
n1 enable = 0;
n1 enableLatch = 0;
n1 irq = 0;
n1 line = 0;
n8 period = 0;
@@ -106,7 +108,8 @@ protected:
n1 keyOn = 0;
n1 keyLine = 0;
n1 lfoEnable = 0;
n1 tremoloEnable = 0;
n5 keyScale = 0;
n3 detune = 0;
n4 multiple = 0;
n7 totalLevel = 0;
@@ -140,7 +143,7 @@ protected:
n32 steps = 0;
n10 value = 0x3ff;
n2 keyScale = 0;
n2 rateScaling = 0;
n5 attackRate = 0;
n5 decayRate = 0;
n5 sustainRate = 0;
+7 -4
View File
@@ -9,7 +9,6 @@ namespace ares {
io.portCHigherInput = 1;
io.portAInput = 1;
io.groupAMode = 0;
io.ioMode = 0;
state.portA = 0xff;
state.portB = 0xff;
state.portC = 0xff;
@@ -43,15 +42,20 @@ namespace ares {
}
auto I8255::writeControl(n8 data) -> void {
if(data.bit(7) == 0) {
n3 bitSelect = data.bit(1, 3);
state.portC.bit(bitSelect) = data.bit(0);
writePortC(state.portC);
return;
}
io.portCLowerInput = data.bit(0);
io.portBInput = data.bit(1);
io.groupBMode = data.bit(2);
io.portCHigherInput = data.bit(3);
io.portAInput = data.bit(4);
io.groupAMode = data.bit(5,6);
io.ioMode = data.bit(7);
if(!io.ioMode) debug(unimplemented, "[I8255] BSR Mode");
if(io.groupAMode != 0) debug(unimplemented, "[I8255] Group A Mode != 0");
if(io.groupBMode != 0) debug(unimplemented, "[I8255] Group B Mode != 0");
}
@@ -63,7 +67,6 @@ namespace ares {
s(io.portCHigherInput);
s(io.portAInput);
s(io.groupAMode);
s(io.ioMode);
s(state.portA);
s(state.portB);
-1
View File
@@ -23,7 +23,6 @@ namespace ares {
n1 portCHigherInput;
n1 portAInput;
n2 groupAMode;
n1 ioMode;
} io;
struct State {
@@ -9,6 +9,7 @@ namespace ares {
#include "instruction.cpp"
#include "instructions-arm.cpp"
#include "instructions-thumb.cpp"
#include "coprocessor.cpp"
#include "serialization.cpp"
#include "disassembler.cpp"
@@ -19,7 +20,9 @@ ARM7TDMI::ARM7TDMI() {
auto ARM7TDMI::power() -> void {
processor = {};
processor.r15.modify = [&] { pipeline.reload = true; };
processor.r15.modify = [&] { processor.r15.data &= ~1; pipeline.reload = true; };
processor.rNULL.modify = [&] { processor.rNULL.data = 0; };
processor.spsrNULL.readonly = true;
pipeline = {};
carry = 0;
irq = 0;
+57 -23
View File
@@ -6,15 +6,13 @@ namespace ares {
struct ARM7TDMI {
enum : u32 {
Nonsequential = 1 << 0, //N cycle
Sequential = 1 << 1, //S cycle
Load = 1 << 0, //load operation
Store = 1 << 1, //store operation
Prefetch = 1 << 2, //instruction fetch
Byte = 1 << 3, // 8-bit access
Half = 1 << 4, //16-bit access
Word = 1 << 5, //32-bit access
Load = 1 << 6, //load operation
Store = 1 << 7, //store operation
Signed = 1 << 8, //sign-extend
Signed = 1 << 6, //sign-extend
};
virtual auto step(u32 clocks) -> void = 0;
@@ -22,6 +20,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();
@@ -42,6 +42,7 @@ struct ARM7TDMI {
auto load(u32 mode, n32 address) -> n32;
auto write(u32 mode, n32 address, n32 word) -> void;
auto store(u32 mode, n32 address, n32 word) -> void;
auto endBurst() -> void { nonsequential = true; return; }
//algorithms.cpp
auto ADD(n32, n32, bool) -> n32;
@@ -56,6 +57,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;
@@ -67,21 +69,25 @@ struct ARM7TDMI {
auto armMoveToStatus(n4 field, n1 source, n32 data) -> void;
auto armInstructionBranch(i24, n1) -> void;
auto armInstructionBranchExchangeRegister(n4) -> void;
auto armInstructionBranchExchangeRegister(n4, n4, n4, n1) -> void;
auto armInstructionCoprocessorDataProcessing(n4, n3, n4, n4, n4, n4) -> void;
auto armInstructionDataImmediate(n8, n4, n4, n4, n1, n4) -> void;
auto armInstructionDataImmediateShift(n4, n2, n5, n4, n4, n1, n4) -> void;
auto armInstructionDataRegisterShift(n4, n2, n4, n4, n4, n1, n4) -> void;
auto armInstructionLoadImmediate(n8, n1, n4, n4, n1, n1, n1) -> void;
auto armInstructionLoadRegister(n4, n1, n4, n4, n1, n1, n1) -> void;
auto armInstructionMemorySwap(n4, n4, n4, n1) -> void;
auto armInstructionMoveHalfImmediate(n8, n4, n4, n1, n1, n1, n1) -> void;
auto armInstructionMoveHalfRegister(n4, n4, n4, n1, n1, n1, n1) -> void;
auto armInstructionMoveImmediateOffset(n12, n4, n4, n1, n1, n1, n1, n1) -> void;
auto armInstructionMoveMultiple(n16, n4, n1, n1, n1, n1, n1) -> void;
auto armInstructionMoveRegisterOffset(n4, n2, n5, n4, n4, n1, n1, n1, n1, n1) -> void;
auto armInstructionMoveSignedImmediate(n8, n1, n4, n4, n1, n1, n1, n1) -> void;
auto armInstructionMoveSignedRegister(n4, n1, n4, n4, n1, n1, n1, n1) -> void;
auto armInstructionMoveToCoprocessorFromRegister(n4, n3, n4, n4, n4, n3) -> void;
auto armInstructionMoveToRegisterFromCoprocessor(n4, n3, n4, n4, n4, n3) -> void;
auto armInstructionMoveToRegisterFromRegister(n4, n4) -> void;
auto armInstructionMoveToRegisterFromStatus(n4, n1) -> void;
auto armInstructionMoveToStatusFromImmediate(n8, n4, n4, n1) -> void;
auto armInstructionMoveToStatusFromRegister(n4, n4, n1) -> void;
auto armInstructionMoveToStatusFromRegister(n4, n2, n5, n4, n1) -> void;
auto armInstructionMultiply(n4, n4, n4, n4, n1, n1) -> void;
auto armInstructionMultiplyLong(n4, n4, n4, n4, n1, n1, n1) -> void;
auto armInstructionSoftwareInterrupt(n24 immediate) -> void;
@@ -145,21 +151,31 @@ struct ARM7TDMI {
};
operator u32() const {
return m << 0 | t << 5 | f << 6 | i << 7 | v << 28 | c << 29 | z << 30 | n << 31;
return m << 0 | 1 << 4 | t << 5 | f << 6 | i << 7 | v << 28 | c << 29 | z << 30 | n << 31;
}
auto operator=(n32 data) -> PSR& {
m = data.bit(0,4);
t = data.bit(5);
f = data.bit(6);
i = data.bit(7);
v = data.bit(28);
c = data.bit(29);
z = data.bit(30);
n = data.bit(31);
set(0b1111, data);
return *this;
}
auto set(n4 field, n32 data) -> void {
if(readonly) return;
if(field.bit(0)) {
m = data.bit(0,4) | 0x10;
t = data.bit(5);
f = data.bit(6);
i = data.bit(7);
}
if(field.bit(3)) {
v = data.bit(28);
c = data.bit(29);
z = data.bit(30);
n = data.bit(31);
}
}
//serialization.cpp
auto serialize(serializer&) -> void;
@@ -171,6 +187,8 @@ struct ARM7TDMI {
b1 c; //carry
b1 z; //zero
b1 n; //negative
b1 readonly;
};
struct Processor {
@@ -179,6 +197,8 @@ struct ARM7TDMI {
GPR r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
PSR cpsr;
GPR rNULL; //read-only, used when no register is mapped to r(13) or r(14)
PSR spsrNULL; //read-only, used when no SPSR is mapped
struct FIQ {
GPR r8, r9, r10, r11, r12, r13, r14;
@@ -214,10 +234,10 @@ struct ARM7TDMI {
n32 address;
n32 instruction;
b1 thumb; //not used by fetch stage
b1 irq; //not used by fetch stage
};
n1 reload = 1;
n1 nonsequential = 1;
Instruction fetch;
Instruction decode;
Instruction execute;
@@ -226,27 +246,41 @@ struct ARM7TDMI {
n32 opcode;
b1 carry;
b1 irq;
b1 nonsequential;
function<void (n32 opcode)> armInstruction[4096];
function<void ()> thumbInstruction[65536];
//coprocessor.cpp
auto bindCDP(n4 id, function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void;
auto bindMCR(n4 id, function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
auto bindMRC(n4 id, function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> CDP[16];
function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> MCR[16];
function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> MRC[16];
//disassembler.cpp
auto armDisassembleBranch(i24, n1) -> string;
auto armDisassembleBranchExchangeRegister(n4) -> string;
auto armDisassembleBranchExchangeRegister(n4, n4, n4, n1) -> string;
auto armDisassembleCoprocessorDataProcessing(n4, n3, n4, n4, n4, n4) -> string;
auto armDisassembleDataImmediate(n8, n4, n4, n4, n1, n4) -> string;
auto armDisassembleDataImmediateShift(n4, n2, n5, n4, n4, n1, n4) -> string;
auto armDisassembleDataRegisterShift(n4, n2, n4, n4, n4, n1, n4) -> string;
auto armDisassembleLoadImmediate(n8, n1, n4, n4, n1, n1, n1) -> string;
auto armDisassembleLoadRegister(n4, n1, n4, n4, n1, n1, n1) -> string;
auto armDisassembleMemorySwap(n4, n4, n4, n1) -> string;
auto armDisassembleMoveHalfImmediate(n8, n4, n4, n1, n1, n1, n1) -> string;
auto armDisassembleMoveHalfRegister(n4, n4, n4, n1, n1, n1, n1) -> string;
auto armDisassembleMoveImmediateOffset(n12, n4, n4, n1, n1, n1, n1, n1) -> string;
auto armDisassembleMoveMultiple(n16, n4, n1, n1, n1, n1, n1) -> string;
auto armDisassembleMoveRegisterOffset(n4, n2, n5, n4, n4, n1, n1, n1, n1, n1) -> string;
auto armDisassembleMoveSignedImmediate(n8, n1, n4, n4, n1, n1, n1, n1) -> string;
auto armDisassembleMoveSignedRegister(n4, n1, n4, n4, n1, n1, n1, n1) -> string;
auto armDisassembleMoveToCoprocessorFromRegister(n4, n3, n4, n4, n4, n3) -> string;
auto armDisassembleMoveToRegisterFromCoprocessor(n4, n3, n4, n4, n4, n3) -> string;
auto armDisassembleMoveToRegisterFromRegister(n4, n4) -> string;
auto armDisassembleMoveToRegisterFromStatus(n4, n1) -> string;
auto armDisassembleMoveToStatusFromImmediate(n8, n4, n4, n1) -> string;
auto armDisassembleMoveToStatusFromRegister(n4, n4, n1) -> string;
auto armDisassembleMoveToStatusFromRegister(n4, n2, n5, n4, n1) -> string;
auto armDisassembleMultiply(n4, n4, n4, n4, n1, n1) -> string;
auto armDisassembleMultiplyLong(n4, n4, n4, n4, n1, n1, n1) -> string;
auto armDisassembleSoftwareInterrupt(n24) -> string;
@@ -0,0 +1,11 @@
auto ARM7TDMI::bindCDP(n4 id, function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void {
CDP[id] = handler;
}
auto ARM7TDMI::bindMCR(n4 id, function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
MCR[id] = handler;
}
auto ARM7TDMI::bindMRC(n4 id, function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
MRC[id] = handler;
}
@@ -17,12 +17,12 @@ auto ARM7TDMI::disassembleInstruction(maybe<n32> pc, maybe<boolean> thumb) -> st
_pc = pc();
if(!thumb()) {
n32 opcode = getDebugger(Word | Nonsequential, _pc & ~3);
n32 opcode = getDebugger(Word, _pc & ~3);
n12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
_c = _conditions[opcode >> 28];
return pad(armDisassemble[index](opcode), -40);
} else {
n16 opcode = getDebugger(Half | Nonsequential, _pc & ~1);
n16 opcode = getDebugger(Half, _pc & ~1);
return pad(thumbDisassemble[opcode](), -40);
}
}
@@ -64,10 +64,16 @@ auto ARM7TDMI::armDisassembleBranch
}
auto ARM7TDMI::armDisassembleBranchExchangeRegister
(n4 m) -> string {
(n4 m, n4 d, n4 field, n1 mode) -> string {
return {"bx", _c, " ", _r[m]};
}
auto ARM7TDMI::armDisassembleCoprocessorDataProcessing
(n4 cm, n3 op2, n4 cpid, n4 cd, n4 cn, n4 op1) -> string {
return {"cdp", _c, " p", cpid, ", ", op1, ", cr", cd,
", cr", cn, ", cr", cm, ", ", op2};
}
auto ARM7TDMI::armDisassembleDataImmediate
(n8 immediate, n4 shift, n4 d, n4 n, n1 save, n4 mode) -> string {
static const string opcode[] = {
@@ -118,30 +124,6 @@ auto ARM7TDMI::armDisassembleDataRegisterShift
" ", _r[s]};
}
auto ARM7TDMI::armDisassembleLoadImmediate
(n8 immediate, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> string {
string data;
if(n == 15) data = {" =0x", hex(getDebugger((half ? Half : Byte) | Nonsequential,
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
return {"ldr", _c, half ? "sh" : "sb", " ",
_r[d], ",[", _r[n],
pre == 0 ? "]" : "",
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
pre == 1 ? "]" : "",
pre == 0 || writeback ? "!" : "", data};
}
auto ARM7TDMI::armDisassembleLoadRegister
(n4 m, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> string {
return {"ldr", _c, half ? "sh" : "sb", " ",
_r[d], ",[", _r[n],
pre == 0 ? "]" : "",
",", up ? "+" : "-", _r[m],
pre == 1 ? "]" : "",
pre == 0 || writeback ? "!" : ""};
}
auto ARM7TDMI::armDisassembleMemorySwap
(n4 m, n4 d, n4 n, n1 byte) -> string {
return {"swp", _c, byte ? "b" : "", " ", _r[d], ",", _r[m], ",[", _r[n], "]"};
@@ -150,7 +132,7 @@ auto ARM7TDMI::armDisassembleMemorySwap
auto ARM7TDMI::armDisassembleMoveHalfImmediate
(n8 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
string data;
if(n == 15) data = {" =0x", hex(getDebugger(Half | Nonsequential, _pc + (up ? +immediate : -immediate)), 4L)};
if(n == 15) data = {" =0x", hex(getDebugger(Half, _pc + (up ? +immediate : -immediate)), 4L)};
return {mode ? "ldr" : "str", _c, "h ",
_r[d], ",[", _r[n],
@@ -173,7 +155,7 @@ auto ARM7TDMI::armDisassembleMoveHalfRegister
auto ARM7TDMI::armDisassembleMoveImmediateOffset
(n12 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 byte, n1 up, n1 pre) -> string {
string data;
if(n == 15) data = {" =0x", hex(getDebugger((byte ? Byte : Word) | Nonsequential,
if(n == 15) data = {" =0x", hex(getDebugger((byte ? Byte : Word),
_pc + 8 + (up ? +immediate : -immediate)), byte ? 2L : 4L)};
return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n],
pre == 0 ? "]" : "",
@@ -212,6 +194,47 @@ auto ARM7TDMI::armDisassembleMoveRegisterOffset
pre == 0 || writeback ? "!" : ""};
}
auto ARM7TDMI::armDisassembleMoveSignedImmediate
(n8 immediate, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
string data;
if(n == 15) data = {" =0x", hex(getDebugger((half ? Half : Byte),
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
return {mode ? "ldr" : "str", _c, half ? "sh" : "sb", " ",
_r[d], ",[", _r[n],
pre == 0 ? "]" : "",
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
pre == 1 ? "]" : "",
pre == 0 || writeback ? "!" : "", data};
}
auto ARM7TDMI::armDisassembleMoveSignedRegister
(n4 m, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> string {
return {mode ? "ldr" : "str", _c, half ? "sh" : "sb", " ",
_r[d], ",[", _r[n],
pre == 0 ? "]" : "",
",", up ? "+" : "-", _r[m],
pre == 1 ? "]" : "",
pre == 0 || writeback ? "!" : ""};
}
auto ARM7TDMI::armDisassembleMoveToCoprocessorFromRegister
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> string {
return {"mcr", _c, " p", cpid, ", ", op1, ", ", _r[d],
", cr", cn, ", cr", cm, ", ", op2};
}
auto ARM7TDMI::armDisassembleMoveToRegisterFromCoprocessor
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> string {
return {"mrc", _c, " p", cpid, ", ", op1, ", ", _r[d],
", cr", cn, ", cr", cm, ", ", op2};
}
auto ARM7TDMI::armDisassembleMoveToRegisterFromRegister
(n4 d, n4 n) -> string {
return {"mov", _c, " ", _r[d], ",", _r[n]};
}
auto ARM7TDMI::armDisassembleMoveToRegisterFromStatus
(n4 d, n1 mode) -> string {
return {"mrs", _c, " ", _r[d], ",", mode ? "spsr" : "cpsr"};
@@ -229,13 +252,18 @@ auto ARM7TDMI::armDisassembleMoveToStatusFromImmediate
}
auto ARM7TDMI::armDisassembleMoveToStatusFromRegister
(n4 m, n4 field, n1 mode) -> string {
(n4 m, n2 type, n5 shift, n4 field, n1 mode) -> string {
return {"msr", _c, " ", mode ? "spsr:" : "cpsr:",
field.bit(0) ? "c" : "",
field.bit(1) ? "x" : "",
field.bit(2) ? "s" : "",
field.bit(3) ? "f" : "",
",", _r[m]};
",", _r[m],
type == 0 && shift ? string{" lsl #", shift} : string{},
type == 1 ? string{" lsr #", shift ? (u32)shift : 32} : string{},
type == 2 ? string{" asr #", shift ? (u32)shift : 32} : string{},
type == 3 && shift ? string{" ror #", shift} : string{},
type == 3 && !shift ? " rrx" : ""};
}
auto ARM7TDMI::armDisassembleMultiply
@@ -276,7 +304,7 @@ auto ARM7TDMI::thumbDisassembleALU
auto ARM7TDMI::thumbDisassembleALUExtended
(n4 d, n4 m, n2 mode) -> string {
static const string opcode[] = {"add", "sub", "mov"};
static const string opcode[] = {"add", "cmp", "mov"};
if(d == 8 && m == 8 && mode == 2) return {"nop"};
return {opcode[mode], " ", _r[d], ",", _r[m]};
}
@@ -308,7 +336,7 @@ auto ARM7TDMI::thumbDisassembleBranchExchange
auto ARM7TDMI::thumbDisassembleBranchFarPrefix
(i11 displacementHi) -> string {
n11 displacementLo = getDebugger(Half | Nonsequential, (_pc & ~1) + 2);
n11 displacementLo = getDebugger(Half, (_pc & ~1) + 2);
i22 displacement = displacementHi << 11 | displacementLo << 0;
n32 address = _pc + 4 + displacement * 2;
return {"bl 0x", hex(address, 8L)};
@@ -340,7 +368,7 @@ auto ARM7TDMI::thumbDisassembleImmediate
auto ARM7TDMI::thumbDisassembleLoadLiteral
(n8 displacement, n3 d) -> string {
n32 address = ((_pc + 4) & ~3) + (displacement << 2);
n32 data = getDebugger(Word | Nonsequential, address);
n32 data = getDebugger(Word, address);
return {"ldr ", _r[d], ",[pc,#0x", hex(address, 8L), "] =0x", hex(data, 8L)};
}
+143 -68
View File
@@ -1,36 +1,30 @@
auto ARM7TDMI::reload() -> void {
u32 size = !cpsr().t ? Word : Half;
pipeline.reload = false;
endBurst();
pipeline.fetch.address = r(15);
pipeline.fetch.instruction = read(Prefetch | size, 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) {
pipeline.nonsequential = false;
sequential = Nonsequential;
}
u32 mask = !cpsr().t ? 3 : 1;
u32 size = !cpsr().t ? Word : Half;
r(15).data += size >> 3;
pipeline.fetch.address = r(15) & ~mask;
pipeline.fetch.instruction = read(Prefetch | size | sequential, pipeline.fetch.address);
pipeline.fetch.address = r(15);
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
}
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;
@@ -81,13 +75,31 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments \
opcode.bit( 0, 3) /* m */
{
auto opcode = pattern(".... 0001 0010 ---- ---- ---- 0001 ????");
opcode.bit( 0, 3), /* m */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19), /* field */ \
opcode.bit(22) /* mode */
for(n3 _ : range(8))
for(n1 mode : range(2)) {
auto opcode = pattern(".... 0001 0??0 ???? ???? ---- 0??1 ????") | _.bit(0,1) << 5 | _.bit(2) << 21 | mode << 22;
bind(opcode, BranchExchangeRegister);
}
#undef arguments
#define arguments \
opcode.bit( 0, 3), /* cm */ \
opcode.bit( 5, 7), /* op2 */ \
opcode.bit( 8,11), /* cpid */ \
opcode.bit(12,15), /* cd */ \
opcode.bit(16,19), /* cn */ \
opcode.bit(20,23) /* op1 */
for(n3 op2 : range(8))
for(n4 op1 : range(16)) {
auto opcode = pattern(".... 1110 ???? ???? ???? ???? ???0 ????") | op2 << 5 | op1 << 20;
bind(opcode, CoprocessorDataProcessing);
}
#undef arguments
#define arguments \
opcode.bit( 0, 7), /* immediate */ \
opcode.bit( 8,11), /* shift */ \
@@ -139,47 +151,14 @@ auto ARM7TDMI::armInitialize() -> void {
}
#undef arguments
#define arguments \
opcode.bit( 0, 3) << 0 | opcode.bit( 8,11) << 4, /* immediate */ \
opcode.bit( 5), /* half */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19), /* n */ \
opcode.bit(21), /* writeback */ \
opcode.bit(23), /* up */ \
opcode.bit(24) /* pre */
for(n1 half : range(2))
for(n1 writeback : range(2))
for(n1 up : range(2))
for(n1 pre : range(2)) {
auto opcode = pattern(".... 000? ?1?1 ???? ???? ???? 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
bind(opcode, LoadImmediate);
}
#undef arguments
#define arguments \
opcode.bit( 0, 3), /* m */ \
opcode.bit( 5), /* half */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19), /* n */ \
opcode.bit(21), /* writeback */ \
opcode.bit(23), /* up */ \
opcode.bit(24) /* pre */
for(n1 half : range(2))
for(n1 writeback : range(2))
for(n1 up : range(2))
for(n1 pre : range(2)) {
auto opcode = pattern(".... 000? ?0?1 ???? ???? ---- 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
bind(opcode, LoadRegister);
}
#undef arguments
#define arguments \
opcode.bit( 0, 3), /* m */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19), /* n */ \
opcode.bit(22) /* byte */
for(n3 _ : range(8))
for(n1 byte : range(2)) {
auto opcode = pattern(".... 0001 0?00 ???? ???? ---- 1001 ????") | byte << 22;
auto opcode = pattern(".... 0001 ???? ???? ???? ---- 1001 ????") | _.bit(0,1) << 20 | byte << 22 | _.bit(2) << 23;
bind(opcode, MemorySwap);
}
#undef arguments
@@ -283,11 +262,88 @@ auto ARM7TDMI::armInitialize() -> void {
}
#undef arguments
#define arguments \
opcode.bit( 0, 3) << 0 | opcode.bit( 8,11) << 4, /* immediate */ \
opcode.bit( 5), /* half */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19), /* n */ \
opcode.bit(20), /* mode */ \
opcode.bit(21), /* writeback */ \
opcode.bit(23), /* up */ \
opcode.bit(24) /* pre */
for(n1 half : range(2))
for(n1 mode : range(2))
for(n1 writeback : range(2))
for(n1 up : range(2))
for(n1 pre : range(2)) {
auto opcode = pattern(".... 000? ?1?? ???? ???? ???? 11?1 ????") | half << 5 | mode << 20 | writeback << 21 | up << 23 | pre << 24;
bind(opcode, MoveSignedImmediate);
}
#undef arguments
#define arguments \
opcode.bit( 0, 3), /* m */ \
opcode.bit( 5), /* half */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19), /* n */ \
opcode.bit(20), /* mode */ \
opcode.bit(21), /* writeback */ \
opcode.bit(23), /* up */ \
opcode.bit(24) /* pre */
for(n1 half : range(2))
for(n1 mode : range(2))
for(n1 writeback : range(2))
for(n1 up : range(2))
for(n1 pre : range(2)) {
auto opcode = pattern(".... 000? ?0?? ???? ???? ---- 11?1 ????") | half << 5 | mode << 20 | writeback << 21 | up << 23 | pre << 24;
bind(opcode, MoveSignedRegister);
}
#undef arguments
#define arguments \
opcode.bit( 0, 3), /* cm */ \
opcode.bit( 5, 7), /* op2 */ \
opcode.bit( 8,11), /* cpid */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19), /* cn */ \
opcode.bit(21,23) /* op1 */
for(n3 op2 : range(8))
for(n3 op1 : range(8)) {
auto opcode = pattern(".... 1110 ???0 ???? ???? ???? ???1 ????") | op2 << 5 | op1 << 21;
bind(opcode, MoveToCoprocessorFromRegister);
}
#undef arguments
#define arguments \
opcode.bit( 0, 3), /* cm */ \
opcode.bit( 5, 7), /* op2 */ \
opcode.bit( 8,11), /* cpid */ \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19), /* cn */ \
opcode.bit(21,23) /* op1 */
for(n3 op2 : range(8))
for(n3 op1 : range(8)) {
auto opcode = pattern(".... 1110 ???1 ???? ???? ???? ???1 ????") | op2 << 5 | op1 << 21;
bind(opcode, MoveToRegisterFromCoprocessor);
}
#undef arguments
#define arguments \
opcode.bit(12,15), /* d */ \
opcode.bit(16,19) /* n */
for(n5 _ : range(32)) {
//undocumented instruction, equivalent to "mov rd, rn"
auto opcode = pattern(".... 0011 0?00 ???? ???? ---- ???? ----") | _.bit(0,3) << 4 | _.bit(4) << 22;
bind(opcode, MoveToRegisterFromRegister);
}
#undef arguments
#define arguments \
opcode.bit(12,15), /* d */ \
opcode.bit(22) /* mode */
for(n3 _ : range(8))
for(n1 mode : range(2)) {
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- 0000 ----") | mode << 22;
auto opcode = pattern(".... 0001 0?00 ---- ???? ---- ???0 ----") | _ << 5 | mode << 22;
bind(opcode, MoveToRegisterFromStatus);
}
#undef arguments
@@ -306,10 +362,14 @@ auto ARM7TDMI::armInitialize() -> void {
#define arguments \
opcode.bit( 0, 3), /* m */ \
opcode.bit( 5, 6), /* type */ \
opcode.bit( 7,11), /* shift */ \
opcode.bit(16,19), /* field */ \
opcode.bit(22) /* mode */
for(n2 type : range(4))
for(n1 shiftLo : range(2))
for(n1 mode : range(2)) {
auto opcode = pattern(".... 0001 0?10 ???? ---- ---- 0000 ????") | mode << 22;
auto opcode = pattern(".... 0001 0?10 ???? ---- ???? ???0 ????") | type << 5 | shiftLo << 7 | mode << 22;
bind(opcode, MoveToStatusFromRegister);
}
#undef arguments
@@ -322,8 +382,9 @@ auto ARM7TDMI::armInitialize() -> void {
opcode.bit(20), /* save */ \
opcode.bit(21) /* accumulate */
for(n1 save : range(2))
for(n1 accumulate : range(2)) {
auto opcode = pattern(".... 0000 00?? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21;
for(n1 accumulate : range(2))
for(n1 _ : range(2)) {
auto opcode = pattern(".... 0000 0??? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21 | _ << 22;
bind(opcode, Multiply);
}
#undef arguments
@@ -354,15 +415,28 @@ auto ARM7TDMI::armInitialize() -> void {
#undef arguments
#define arguments
for(n12 id : range(4096)) {
if(armInstruction[id]) continue;
auto opcode = pattern(".... ???? ???? ---- ---- ---- ???? ----") | id.bit(0,3) << 4 | id.bit(4,11) << 20;
for(n8 _ : range(256)) {
//architecturally undefined
auto opcode = pattern(".... 011? ???? ---- ---- ---- ???1 ----") | _.bit(0,2) << 5 | _.bit(3,7) << 20;
bind(opcode, Undefined);
}
for(n8 _ : range(256)) {
//load to coprocessor
auto opcode = pattern(".... 110? ???1 ---- ---- ---- ???? ----") | _.bit(0,3) << 4 | _.bit(4,7) << 21;
bind(opcode, Undefined);
}
for(n8 _ : range(256)) {
//store from coprocessor
auto opcode = pattern(".... 110? ???0 ---- ---- ---- ???? ----") | _.bit(0,3) << 4 | _.bit(4,7) << 21;
bind(opcode, Undefined);
}
#undef arguments
#undef bind
#undef pattern
//check that all encodings are bound
for(n12 index : range(4096)) assert(armInstruction[index]);
}
auto ARM7TDMI::thumbInitialize() -> void {
@@ -419,9 +493,9 @@ auto ARM7TDMI::thumbInitialize() -> void {
bind(opcode, AdjustStack, immediate, mode);
}
for(n3 _ : range(8))
for(n4 _ : range(16))
for(n4 m : range(16)) {
auto opcode = pattern("0100 0111 0??? ?---") | _ << 0 | m << 3;
auto opcode = pattern("0100 0111 ???? ?---") | _.bit(0,2) << 0 | m << 3 | _.bit(3) << 7;
bind(opcode, BranchExchange, m);
}
@@ -442,6 +516,7 @@ auto ARM7TDMI::thumbInitialize() -> void {
for(n8 displacement : range(256))
for(n4 condition : range(16)) {
if(condition == 14) continue; //BAL
if(condition == 15) continue; //BNV
auto opcode = pattern("1101 ???? ???? ????") | displacement << 0 | condition << 8;
bind(opcode, BranchTest, displacement, condition);
@@ -24,24 +24,12 @@ auto ARM7TDMI::armALU(n4 mode, n4 d, n32 rn, n32 rm) -> void {
}
auto ARM7TDMI::armMoveToStatus(n4 field, n1 mode, n32 data) -> void {
if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return;
PSR& psr = mode ? spsr() : cpsr();
if(field.bit(0)) {
if(mode || privileged()) {
psr.m = data.bit(0,4);
psr.t = data.bit(5);
psr.f = data.bit(6);
psr.i = data.bit(7);
if(!mode && psr.t) r(15).data += 2;
}
}
if(field.bit(3)) {
psr.v = data.bit(28);
psr.c = data.bit(29);
psr.z = data.bit(30);
psr.n = data.bit(31);
if(mode) {
spsr().set(field, data);
} else {
if(!privileged()) field.bit(0) = 0;
cpsr().set(field, data);
if(cpsr().t) r(15).data += 2;
}
}
@@ -54,10 +42,21 @@ auto ARM7TDMI::armInstructionBranch
}
auto ARM7TDMI::armInstructionBranchExchangeRegister
(n4 m) -> void {
(n4 m, n4 d, n4 field, n1 mode) -> void {
n32 address = r(m);
cpsr().t = address.bit(0);
r(15) = address;
if((field & 0b1001) == 0b1001) {
PSR& psr = mode ? spsr() : cpsr();
psr.t = address.bit(0);
} else {
armMoveToStatus(field, mode, address);
}
r(d) = address;
}
auto ARM7TDMI::armInstructionCoprocessorDataProcessing
(n4 cm, n3 op2, n4 cpid, n4 cd, n4 cn, n4 op1) -> void {
if(!CDP[cpid]) return armInstructionUndefined();
CDP[cpid](cm, op2, cd, cn, op1);
}
auto ARM7TDMI::armInstructionDataImmediate
@@ -87,66 +86,43 @@ auto ARM7TDMI::armInstructionDataImmediateShift
auto ARM7TDMI::armInstructionDataRegisterShift
(n4 m, n2 type, n4 s, n4 d, n4 n, n1 save, n4 mode) -> void {
n8 rs = r(s) + (s == 15 ? 4 : 0);
n8 rs = r(s);
n32 rn = r(n) + (n == 15 ? 4 : 0);
n32 rm = r(m) + (m == 15 ? 4 : 0);
carry = cpsr().c;
idle();
switch(type) {
case 0: rm = LSL(rm, rs < 33 ? rs : (n8)33); break;
case 1: rm = LSR(rm, rs < 33 ? rs : (n8)33); break;
case 2: rm = ASR(rm, rs < 32 ? rs : (n8)32); break;
case 3: if(rs) rm = ROR(rm, rs & 31 ? u32(rs & 31) : 32); break;
case 0: rm = LSL(rm, rs); break;
case 1: rm = LSR(rm, rs); break;
case 2: rm = ASR(rm, rs); break;
case 3: rm = ROR(rm, rs); break;
}
armALU(mode, d, rn, rm);
}
auto ARM7TDMI::armInstructionLoadImmediate
(n8 immediate, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> void {
n32 rn = r(n);
n32 rd = r(d);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback) r(n) = rn;
r(d) = rd;
}
auto ARM7TDMI::armInstructionLoadRegister
(n4 m, n1 half, n4 d, n4 n, n1 writeback, n1 up, n1 pre) -> void {
n32 rn = r(n);
n32 rm = r(m);
n32 rd = r(d);
if(pre == 1) rn = up ? rn + rm : rn - rm;
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback) r(n) = rn;
r(d) = rd;
}
auto ARM7TDMI::armInstructionMemorySwap
(n4 m, n4 d, n4 n, n1 byte) -> void {
n32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
n32 rm = r(m) + (m == 15 ? 4 : 0);
lock();
n32 word = load((byte ? Byte : Word), r(n));
store((byte ? Byte : Word), r(n), rm);
r(d) = word;
unlock();
}
auto ARM7TDMI::armInstructionMoveHalfImmediate
(n8 immediate, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
n32 rn = r(n);
n32 rd = r(d);
n32 rd = r(d) + (d == 15 ? 4 : 0);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
if(mode == 1) rd = load(Half | Nonsequential, rn);
if(mode == 0) store(Half | Nonsequential, rn, rd);
if(mode == 1) rd = load(Half, rn);
if(mode == 0) store(Half, rn, rd);
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback) r(n) = rn;
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
if(mode == 1) r(d) = rd;
}
@@ -154,14 +130,14 @@ auto ARM7TDMI::armInstructionMoveHalfRegister
(n4 m, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
n32 rn = r(n);
n32 rm = r(m);
n32 rd = r(d);
n32 rd = r(d) + (d == 15 ? 4 : 0);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(mode == 1) rd = load(Half | Nonsequential, rn);
if(mode == 0) store(Half | Nonsequential, rn, rd);
if(mode == 1) rd = load(Half, rn);
if(mode == 0) store(Half, rn, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback) r(n) = rn;
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
if(mode == 1) r(d) = rd;
}
@@ -171,8 +147,8 @@ auto ARM7TDMI::armInstructionMoveImmediateOffset
n32 rd = r(d) + (d == 15 ? 4 : 0);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
if(mode == 1) rd = load((byte ? Byte : Word), rn);
if(mode == 0) store((byte ? Byte : Word), rn, rd);
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback) r(n) = rn;
@@ -183,34 +159,32 @@ auto ARM7TDMI::armInstructionMoveMultiple
(n16 list, n4 n, n1 mode, n1 writeback, n1 type, n1 up, n1 pre) -> void {
n32 rn = r(n);
n32 bitCount = list ? bit::count(list) : 16;
n32 rnEnd;
if(up == 1) rnEnd = r(n) + bitCount * 4; //IA,IB
if(up == 0) rnEnd = r(n) - bitCount * 4; //DA,DB
if(pre == 0 && up == 1) rn = rn + 0; //IA
if(pre == 1 && up == 1) rn = rn + 4; //IB
if(pre == 1 && up == 0) rn = rn - bitCount * 4 + 0; //DB
if(pre == 0 && up == 0) rn = rn - bitCount * 4 + 4; //DA
if(writeback && mode == 1 && !list.bit(n)) {
if(up == 1) r(n) = r(n) + bitCount * 4; //IA,IB
if(up == 0) r(n) = r(n) - bitCount * 4; //DA,DB
}
auto cpsrMode = cpsr().m;
bool usr = false;
if(type && mode == 1 && !list.bit(15)) usr = true;
if(type && mode == 0) usr = true;
if(usr) cpsr().m = PSR::USR;
u32 sequential = Nonsequential;
if(!list) {
if(mode == 1) r(15) = read(Word | sequential, rn);
if(mode == 0) write(Word | sequential, rn, r(15) + 4);
} else {
for(u32 m : range(16)) {
if(!list.bit(m)) continue;
if(mode == 1) r(m) = read(Word | sequential, rn);
if(mode == 0) write(Word | sequential, rn, r(m) + (m == 15 ? 4 : 0));
rn += 4;
sequential = Sequential;
if(writeback && mode == 1 && !list.bit(n)) r(n) = rnEnd;
endBurst();
if(!list) list.bit(15) = 1;
for(u32 m : range(16)) {
if(!list.bit(m)) continue;
if(mode == 1) r(m) = read(Word, rn);
if(mode == 0) {
write(Word, rn, r(m) + (!(n == 15 && writeback) && m == 15 ? 4 : 0));
if(writeback) r(n) = rnEnd; //writeback occurs after first access
}
rn += 4;
}
if(usr) cpsr().m = cpsrMode;
@@ -221,19 +195,14 @@ auto ARM7TDMI::armInstructionMoveMultiple
cpsr() = spsr();
}
} else {
pipeline.nonsequential = true;
}
if(writeback && mode == 0) {
if(up == 1) r(n) = r(n) + bitCount * 4; //IA,IB
if(up == 0) r(n) = r(n) - bitCount * 4; //DA,DB
endBurst();
}
}
auto ARM7TDMI::armInstructionMoveRegisterOffset
(n4 m, n2 type, n5 shift, n4 d, n4 n, n1 mode, n1 writeback, n1 byte, n1 up, n1 pre) -> void {
n32 rm = r(m);
n32 rd = r(d);
n32 rd = r(d) + (d == 15 ? 4 : 0);
n32 rn = r(n);
carry = cpsr().c;
@@ -245,14 +214,60 @@ auto ARM7TDMI::armInstructionMoveRegisterOffset
}
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
if(mode == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd);
if(mode == 1) rd = load((byte ? Byte : Word), rn);
if(mode == 0) store((byte ? Byte : Word), rn, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback) r(n) = rn;
if(mode == 1) r(d) = rd;
}
auto ARM7TDMI::armInstructionMoveSignedImmediate
(n8 immediate, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
n32 rn = r(n);
n32 rd = r(d) + (d == 15 ? 4 : 0);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
if(mode == 1) rd = load((half ? Half : Byte) | Signed, rn);
if(mode == 0) store((half ? Half : Byte) | Signed, rn, rd);
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
if(mode == 1) r(d) = rd;
}
auto ARM7TDMI::armInstructionMoveSignedRegister
(n4 m, n1 half, n4 d, n4 n, n1 mode, n1 writeback, n1 up, n1 pre) -> void {
n32 rn = r(n);
n32 rm = r(m);
n32 rd = r(d) + (d == 15 ? 4 : 0);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(mode == 1) rd = load((half ? Half : Byte) | Signed, rn);
if(mode == 0) store((half ? Half : Byte) | Signed, rn, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
if(mode == 1) r(d) = rd;
}
auto ARM7TDMI::armInstructionMoveToCoprocessorFromRegister
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> void {
if(!MCR[cpid]) return armInstructionUndefined();
MCR[cpid](r(d), cm, op2, cn, op1);
}
auto ARM7TDMI::armInstructionMoveToRegisterFromCoprocessor
(n4 cm, n3 op2, n4 cpid, n4 d, n4 cn, n3 op1) -> void {
if(!MRC[cpid]) return armInstructionUndefined();
r(d) = MRC[cpid](cm, op2, cn, op1);
}
auto ARM7TDMI::armInstructionMoveToRegisterFromRegister
(n4 d, n4 n) -> void {
r(d) = r(n);
}
auto ARM7TDMI::armInstructionMoveToRegisterFromStatus
(n4 d, n1 mode) -> void {
r(d) = (mode && cpsr().m != PSR::USR && cpsr().m != PSR::SYS) ? spsr() : cpsr();
@@ -266,14 +281,25 @@ auto ARM7TDMI::armInstructionMoveToStatusFromImmediate
}
auto ARM7TDMI::armInstructionMoveToStatusFromRegister
(n4 m, n4 field, n1 mode) -> void {
armMoveToStatus(field, mode, r(m));
(n4 m, n2 type, n5 shift, n4 field, n1 mode) -> void {
n32 rm = r(m);
carry = cpsr().c;
switch(type) {
case 0: rm = LSL(rm, shift); break;
case 1: rm = LSR(rm, shift ? (u32)shift : 32); break;
case 2: rm = ASR(rm, shift ? (u32)shift : 32); break;
case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break;
}
armMoveToStatus(field, mode, rm);
}
auto ARM7TDMI::armInstructionMultiply
(n4 m, n4 s, n4 n, n4 d, n1 save, n1 accumulate) -> void {
if(accumulate) idle();
r(d) = MUL(accumulate ? r(n) : 0, r(m), r(s));
n32 product = MUL(accumulate ? r(n) : 0, r(m), r(s));
if(d != 15) r(d) = product;
}
auto ARM7TDMI::armInstructionMultiplyLong
@@ -300,8 +326,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;
if(l != 15) r(l) = rd >> 0;
if(h != 15) r(h) = rd >> 32;
if(save) {
cpsr().z = rd == 0;
@@ -1,14 +1,15 @@
auto ARM7TDMI::thumbInstructionALU
(n3 d, n3 m, n4 mode) -> void {
carry = cpsr().c;
switch(mode) {
case 0: r(d) = BIT(r(d) & r(m)); break; //AND
case 1: r(d) = BIT(r(d) ^ r(m)); break; //EOR
case 2: r(d) = BIT(LSL(r(d), r(m))); break; //LSL
case 3: r(d) = BIT(LSR(r(d), r(m))); break; //LSR
case 4: r(d) = BIT(ASR(r(d), r(m))); break; //ASR
case 2: r(d) = BIT(LSL(r(d), r(m))); idle(); break; //LSL
case 3: r(d) = BIT(LSR(r(d), r(m))); idle(); break; //LSR
case 4: r(d) = BIT(ASR(r(d), r(m))); idle(); break; //ASR
case 5: r(d) = ADD(r(d), r(m), cpsr().c); break; //ADC
case 6: r(d) = SUB(r(d), r(m), cpsr().c); break; //SBC
case 7: r(d) = BIT(ROR(r(d), r(m))); break; //ROR
case 7: r(d) = BIT(ROR(r(d), r(m))); idle(); break; //ROR
case 8: BIT(r(d) & r(m)); break; //TST
case 9: r(d) = SUB(0, r(m), 1); break; //NEG
case 10: SUB(r(d), r(m), 1); break; //CMP
@@ -24,7 +25,7 @@ auto ARM7TDMI::thumbInstructionALUExtended
(n4 d, n4 m, n2 mode) -> void {
switch(mode) {
case 0: r(d) = r(d) + r(m); break; //ADD
case 1: SUB(r(d), r(m), 1); break; //SUBS
case 1: SUB(r(d), r(m), 1); break; //CMP
case 2: r(d) = r(m); break; //MOV
}
}
@@ -92,6 +93,7 @@ auto ARM7TDMI::thumbInstructionBranchTest
auto ARM7TDMI::thumbInstructionImmediate
(n8 immediate, n3 d, n2 mode) -> void {
carry = cpsr().c;
switch(mode) {
case 0: r(d) = BIT(immediate); break; //MOV
case 1: SUB(r(d), immediate, 1); break; //CMP
@@ -103,81 +105,80 @@ auto ARM7TDMI::thumbInstructionImmediate
auto ARM7TDMI::thumbInstructionLoadLiteral
(n8 displacement, n3 d) -> void {
n32 address = (r(15) & ~3) + (displacement << 2);
r(d) = load(Word | Nonsequential, address);
r(d) = load(Word, address);
}
auto ARM7TDMI::thumbInstructionMoveByteImmediate
(n3 d, n3 n, n5 offset, n1 mode) -> void {
switch(mode) {
case 0: store(Byte | Nonsequential, r(n) + offset, r(d)); break; //STRB
case 1: r(d) = load(Byte | Nonsequential, r(n) + offset); break; //LDRB
case 0: store(Byte, r(n) + offset, r(d)); break; //STRB
case 1: r(d) = load(Byte, r(n) + offset); break; //LDRB
}
}
auto ARM7TDMI::thumbInstructionMoveHalfImmediate
(n3 d, n3 n, n5 offset, n1 mode) -> void {
switch(mode) {
case 0: store(Half | Nonsequential, r(n) + offset * 2, r(d)); break; //STRH
case 1: r(d) = load(Half | Nonsequential, r(n) + offset * 2); break; //LDRH
case 0: store(Half, r(n) + offset * 2, r(d)); break; //STRH
case 1: r(d) = load(Half, r(n) + offset * 2); break; //LDRH
}
}
auto ARM7TDMI::thumbInstructionMoveMultiple
(n8 list, n3 n, n1 mode) -> void {
n32 rn = r(n);
n32 bitCount = list ? bit::count(list) : 16;
n16 rlist = list;
n32 bitCount = rlist ? bit::count(rlist) : 16;
n32 rnEnd = r(n) + bitCount * 4;
if(mode == 1 && !list.bit(n)) r(n) = r(n) + bitCount * 4;
if(mode == 1 && !rlist.bit(n)) r(n) = rnEnd;
u32 sequential = Nonsequential;
if(!list) {
if(mode == 1) r(15) = read(Word | sequential, rn);
if(mode == 0) write(Word | sequential, rn, r(15) + 2);
} else {
for(u32 m : range(8)) {
if(!list.bit(m)) continue;
if(mode == 1) r(m) = read(Word | sequential, rn); //LDMIA
if(mode == 0) write(Word | sequential, rn, r(m)); //STMIA
rn += 4;
sequential = Sequential;
endBurst();
if(!rlist) rlist.bit(15) = 1;
for(u32 m : range(16)) {
if(!rlist.bit(m)) continue;
if(mode == 1) r(m) = read(Word, rn); //LDMIA
if(mode == 0) {
write(Word, rn, r(m) + (m == 15 ? 2 : 0)); //STMIA
r(n) = rnEnd; //writeback occurs after first access
}
rn += 4;
}
if(mode) {
idle();
} else {
pipeline.nonsequential = true;
r(n) = r(n) + bitCount * 4;
endBurst();
}
}
auto ARM7TDMI::thumbInstructionMoveRegisterOffset
(n3 d, n3 n, n3 m, n3 mode) -> void {
switch(mode) {
case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR
case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH
case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
case 3: r(d) = load(Byte | Nonsequential | Signed, r(n) + r(m)); break; //LDSB
case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR
case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH
case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB
case 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH
case 0: store(Word, r(n) + r(m), r(d)); break; //STR
case 1: store(Half, r(n) + r(m), r(d)); break; //STRH
case 2: store(Byte, r(n) + r(m), r(d)); break; //STRB
case 3: r(d) = load(Byte | Signed, r(n) + r(m)); break; //LDSB
case 4: r(d) = load(Word, r(n) + r(m)); break; //LDR
case 5: r(d) = load(Half, r(n) + r(m)); break; //LDRH
case 6: r(d) = load(Byte, r(n) + r(m)); break; //LDRB
case 7: r(d) = load(Half | Signed, r(n) + r(m)); break; //LDSH
}
}
auto ARM7TDMI::thumbInstructionMoveStack
(n8 immediate, n3 d, n1 mode) -> void {
switch(mode) {
case 0: store(Word | Nonsequential, r(13) + immediate * 4, r(d)); break; //STR
case 1: r(d) = load(Word | Nonsequential, r(13) + immediate * 4); break; //LDR
case 0: store(Word, r(13) + immediate * 4, r(d)); break; //STR
case 1: r(d) = load(Word, r(13) + immediate * 4); break; //LDR
}
}
auto ARM7TDMI::thumbInstructionMoveWordImmediate
(n3 d, n3 n, n5 offset, n1 mode) -> void {
switch(mode) {
case 0: store(Word | Nonsequential, r(n) + offset * 4, r(d)); break; //STR
case 1: r(d) = load(Word | Nonsequential, r(n) + offset * 4); break; //LDR
case 0: store(Word, r(n) + offset * 4, r(d)); break; //STR
case 1: r(d) = load(Word, r(n) + offset * 4); break; //LDR
}
}
@@ -198,33 +199,28 @@ auto ARM7TDMI::thumbInstructionSoftwareInterrupt
auto ARM7TDMI::thumbInstructionStackMultiple
(n8 list, n1 lrpc, n1 mode) -> void {
n32 sp = r(13);
n32 bitCount = (list | lrpc) ? (bit::count(list) + lrpc) : 16;
n16 rlist = list;
if(lrpc) {
if(mode == 1) rlist.bit(15) = 1; //POP
if(mode == 0) rlist.bit(14) = 1; //PUSH
}
n32 bitCount = rlist ? bit::count(rlist) : 16;
if(mode == 1) r(13) = r(13) + bitCount * 4; //POP
if(mode == 0) sp = sp - bitCount * 4 + 0; //PUSH
u32 sequential = Nonsequential;
if(bitCount == 16) {
if(mode == 1) r(15) = read(Word | sequential, sp); //POP
if(mode == 0) write(Word | sequential, sp, r(15) + 2); //PUSH
} else {
for(u32 m : range(8)) {
if(!list.bit(m)) continue;
if(mode == 1) r(m) = read(Word | sequential, sp); //POP
if(mode == 0) write(Word | sequential, sp, r(m)); //PUSH
sp += 4;
sequential = Sequential;
}
}
if(lrpc) {
if(mode == 1) r(15) = read(Word | sequential, sp); //POP
if(mode == 0) write(Word | sequential, sp, r(14)); //PUSH
endBurst();
if(!rlist) rlist.bit(15) = 1;
for(u32 m : range(16)) {
if(!rlist.bit(m)) continue;
if(mode == 1) r(m) = read(Word, sp); //POP
if(mode == 0) write(Word, sp, r(m) + (m == 15 ? 2 : 0)); //PUSH
sp += 4;
}
if(mode) {
idle();
} else {
pipeline.nonsequential = true;
endBurst();
r(13) = r(13) - bitCount * 4; //PUSH
}
}
+9 -6
View File
@@ -1,14 +1,16 @@
auto ARM7TDMI::idle() -> void {
pipeline.nonsequential = true;
endBurst();
sleep();
}
auto ARM7TDMI::read(u32 mode, n32 address) -> n32 {
return get(mode, address);
n32 word = get(mode, address);
nonsequential = false; //allows burst transfer to continue
return word;
}
auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
pipeline.nonsequential = true;
endBurst();
auto word = get(Load | mode, address);
if(mode & Half) {
address &= 1;
@@ -28,12 +30,13 @@ auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
}
auto ARM7TDMI::write(u32 mode, n32 address, n32 word) -> void {
pipeline.nonsequential = true;
return set(mode, address, word);
set(mode, address, word);
nonsequential = false; //allows burst transfer to continue
return;
}
auto ARM7TDMI::store(u32 mode, n32 address, n32 word) -> void {
pipeline.nonsequential = true;
endBurst();
if(mode & Half) { word &= 0xffff; word |= word << 16; }
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
return set(Store | mode, address, word);
@@ -14,20 +14,24 @@ inline auto ARM7TDMI::r(n4 index) -> GPR& {
case 11: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r11 : processor.r11;
case 12: return processor.cpsr.m == PSR::FIQ ? processor.fiq.r12 : processor.r12;
case 13: switch(processor.cpsr.m) {
case PSR::USR: return processor.r13;
case PSR::FIQ: return processor.fiq.r13;
case PSR::IRQ: return processor.irq.r13;
case PSR::SVC: return processor.svc.r13;
case PSR::ABT: return processor.abt.r13;
case PSR::UND: return processor.und.r13;
default: return processor.r13;
case PSR::SYS: return processor.r13;
default: return processor.rNULL;
}
case 14: switch(processor.cpsr.m) {
case PSR::USR: return processor.r14;
case PSR::FIQ: return processor.fiq.r14;
case PSR::IRQ: return processor.irq.r14;
case PSR::SVC: return processor.svc.r14;
case PSR::ABT: return processor.abt.r14;
case PSR::UND: return processor.und.r14;
default: return processor.r14;
case PSR::SYS: return processor.r14;
default: return processor.rNULL;
}
case 15: return processor.r15;
}
@@ -46,7 +50,7 @@ inline auto ARM7TDMI::spsr() -> PSR& {
case PSR::ABT: return processor.abt.spsr;
case PSR::UND: return processor.und.spsr;
}
throw;
return processor.spsrNULL;
}
inline auto ARM7TDMI::privileged() const -> bool {
@@ -3,6 +3,7 @@ auto ARM7TDMI::serialize(serializer& s) -> void {
s(pipeline);
s(carry);
s(irq);
s(nonsequential);
}
auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
@@ -23,6 +24,8 @@ auto ARM7TDMI::Processor::serialize(serializer& s) -> void {
s(r14.data);
s(r15.data);
s(cpsr);
s(rNULL.data);
s(spsrNULL);
s(fiq.r8.data);
s(fiq.r9.data);
s(fiq.r10.data);
@@ -54,18 +57,21 @@ auto ARM7TDMI::PSR::serialize(serializer& s) -> void {
s(c);
s(z);
s(n);
s(readonly);
}
auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void {
s(reload);
s(nonsequential);
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);
}
@@ -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;
}
@@ -513,19 +513,19 @@ auto SH2::MOVI(u32 i, u32 n) -> void {
}
//MOV.W @(disp,PC),Rn
NALL_NOINLINE auto SH2::MOVWI(u32 d, u32 n) -> void {
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
NALL_NOINLINE auto SH2::MOVLI(u32 d, u32 n) -> void {
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
NALL_NOINLINE auto SH2::MOVA(u32 d) -> void {
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; }
@@ -150,6 +150,7 @@ auto SH2::internalReadByte(u32 address, n8 data) -> n8 {
data.bit(5) = wdt.wtcsr.tme;
data.bit(6) = wdt.wtcsr.wtit;
data.bit(7) = wdt.wtcsr.ovf;
if(wdt.wtcsr.wtit) debug(unimplemented, "SH2: wdt.wtit = 1");
return data;
//WTCNT: watchdog timer counter
@@ -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;
}
}
@@ -42,17 +42,20 @@ auto V30MZ::interrupt(u8 vector, InterruptSource source) -> bool {
auto V30MZ::interrupt(u8 vector) -> bool {
state.halt = false;
if(!PSW.IE) return false;
if(!state.interrupt || !PSW.IE) return false;
return interrupt(vector, InterruptSource::INT);
}
auto V30MZ::nonMaskableInterrupt() -> bool {
return interrupt(2, InterruptSource::NMI);
auto V30MZ::nonMaskableInterrupt(bool value) -> bool {
state.nmi = value;
return true;
}
#define op(id, name, ...) case id: instruction##name(__VA_ARGS__); break;
auto V30MZ::instruction() -> void {
state.brk = PSW.BRK;
state.interrupt = PSW.IE;
state.poll = 1;
state.prefix = 0;
if(state.halt) return wait(1);
@@ -317,7 +320,8 @@ auto V30MZ::instruction() -> void {
}
if(!state.prefix) prefixFlush();
if(PSW.BRK) interrupt(1, InterruptSource::SingleStep);
if(state.poll && state.nmi) interrupt(2, InterruptSource::NMI);
if(state.poll && state.brk) interrupt(1, InterruptSource::SingleStep);
}
#undef op
@@ -105,7 +105,6 @@ auto V30MZ::instructionReturnInt() -> void {
PS = pop();
PSW = pop();
flush();
state.poll = 0;
}
auto V30MZ::instructionInt3() -> void {
@@ -182,7 +181,6 @@ auto V30MZ::instructionPushFlags() -> void {
auto V30MZ::instructionPopFlags() -> void {
wait(2);
PSW = pop();
state.poll = 0;
}
auto V30MZ::instructionPushAll() -> void {
@@ -21,5 +21,4 @@ auto V30MZ::instructionClearFlag(u32 bit) -> void {
auto V30MZ::instructionSetFlag(u32 bit) -> void {
wait(4);
PSW |= 1 << bit;
if(bit == PSW.IE.bit()) state.poll = 0;
}
@@ -43,21 +43,27 @@ auto V30MZ::instructionUndefined1() -> void {
}
template<u32 size> auto V30MZ::instructionIn() -> void {
wait(6);
// TODO: The exact cycle on which I/O access is performed remains unknown.
wait(5);
setAccumulator<size>(in<size>(fetch<Byte>()));
wait(1);
}
template<u32 size> auto V30MZ::instructionOut() -> void {
// TODO: The exact cycle on which I/O access is performed remains unknown.
wait(6);
out<size>(fetch<Byte>(), getAccumulator<size>());
}
template<u32 size> auto V30MZ::instructionInDW() -> void {
wait(5);
// TODO: The exact cycle on which I/O access is performed remains unknown.
wait(4);
setAccumulator<size>(in<size>(DW));
wait(1);
}
template<u32 size> auto V30MZ::instructionOutDW() -> void {
// TODO: The exact cycle on which I/O access is performed remains unknown.
wait(5);
out<size>(DW, getAccumulator<size>());
}
@@ -14,14 +14,14 @@ auto V30MZ::instructionMoveMemSeg() -> void {
wait(1);
modRM();
setMemory<Word>(getSegment());
state.poll = 0;
}
auto V30MZ::instructionMoveSegMem() -> void {
wait(2);
modRM();
setSegment(getMemory<Word>());
if((modrm.reg & 3) == 3) state.poll = 0;
// delay interrupt polling if stack segment changed
if((modrm.reg & 3) == 2) state.poll = 0;
}
template<u32 size> auto V30MZ::instructionMoveAccMem() -> void {
@@ -2,6 +2,9 @@ auto V30MZ::serialize(serializer& s) -> void {
s(state.halt);
s(state.poll);
s(state.prefix);
s(state.interrupt);
s(state.brk);
s(state.nmi);
s(opcode);
+3
View File
@@ -26,6 +26,9 @@ auto V30MZ::power() -> void {
state.halt = 0;
state.poll = 1;
state.prefix = 0;
state.interrupt = 0;
state.brk = 0;
state.nmi = 0;
opcode = 0;
prefixFlush();
+7 -4
View File
@@ -41,7 +41,7 @@ struct V30MZ {
//instruction.cpp
auto prefixFlush() -> void;
auto interrupt(u8 vector) -> bool;
auto nonMaskableInterrupt() -> bool;
auto nonMaskableInterrupt(bool value) -> bool;
auto instruction() -> void;
//registers.cpp
@@ -237,9 +237,12 @@ struct V30MZ {
auto disassembleContext() -> string;
struct State {
bool halt; //set to true for hlt instruction; blocks execution until next interrupt
bool poll; //set to false to suppress interrupt polling between CPU instructions
bool prefix; //set to true for prefix instructions; prevents flushing of Prefix struct
bool halt; //set to true for hlt instruction; blocks execution until next interrupt
bool poll; //set to false to suppress interrupt polling between CPU instructions
bool prefix; //set to true for prefix instructions; prevents flushing of Prefix struct
bool interrupt; //interrupt enable processor status before CPU instruction execution
bool brk; //breakpoint enable processor status before CPU instruction execution
bool nmi; //non-maskable interrupt requested
} state;
u8 opcode;
+286
View File
@@ -0,0 +1,286 @@
#include <ares/ares.hpp>
#include "s3511a.hpp"
namespace ares {
#include "serialization.cpp"
//calculate time between last play of game and current time;
//increment RTC by said amount of seconds
auto S3511A::load() -> void {
n64 timestamp = 0;
for(auto n : range(8)) timestamp.byte(n) = data[8 + n];
if(!timestamp || !(timestamp + 1)) return initRegs(false); //new save file
if(status() & 0x15) {
//these status bits are always 0; reset state on invalid status.
initRegs(false);
return;
}
timestamp = time(0) - timestamp;
//prevent insurmountable slowdown by limiting skips to 5 years
if(timestamp < 60*60*24*365*5) {
while(timestamp--) tickSecond();
}
}
//save time when game is unloaded
auto S3511A::save() -> void {
n64 timestamp = time(0);
for(auto n : range(8)) data[8 + n] = timestamp.byte(n);
}
auto S3511A::power() -> void {
cs = 0;
sio = 0;
sck = 0;
inBuffer = 0;
outBuffer = 0;
shift = 0;
index = 0;
rwSelect = 0;
regSelect = 0;
cmdLatched = 0;
counter = 0;
}
auto S3511A::tickSecond() -> void {
static auto bcdIncrement = [](n8& data) -> n8 {
if ((data & 0x0F) >= 0x09) {
data = (data & 0xF0) + 0x10;
} else {
data++;
}
return data;
};
if(bcdIncrement(second()) < 0x60) return;
second() = 0;
if(bcdIncrement(minute()) < 0x60) return;
minute() = 0;
if(status() & 0x40) {
//24-hour clock
if((bcdIncrement(hour()) & 0x7F) < 0x24) return;
hour().bit(0,5) = 0;
} else {
//12-hour clock
if((bcdIncrement(hour()) & 0x7F) < 0x12) return;
hour().bit(0,5) = 0;
hour().bit(7) ^= 1;
}
weekday() += 1;
weekday() %= 7;
u32 bcdDaysInMonth[12] = {0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31};
if(year() && !(year() & 3)) bcdDaysInMonth[1]++;
if(bcdIncrement(day()) <= bcdDaysInMonth[month()]) return;
day() = 1;
if(bcdIncrement(month()) <= 0x12) return;
month() = 1;
bcdIncrement(year());
}
auto S3511A::checkAlarm() -> void {
//todo: a lot of this is vaguely informed guesswork.
if(status() & 0x08) {
//per-minute edge/steady
if(counter < 256) irqLevel(1);
if(status() & 0x02 && second() == 0x30 && counter == 0) irqLevel(0);
} else if(status() & 0x02) {
//selected frequency steady
n16 duty = (counter << 1) ^ 0xFFFF;
n16 mask = (alarmHour() | (alarmMinute() << 8));
irqLevel((duty & mask) != 0);
} else if(status() & 0x20) {
//alarm
if(status() & 0x40) {
//24-hour clock
irqLevel((hour() & 0x3F) == (alarmHour() & 0x3F) && (minute() & 0x7F) == (alarmMinute() & 0x7F));
} else {
//12-hour clock
irqLevel((hour() & 0xBF) == (alarmHour() & 0xBF) && (minute() & 0x7F) == (alarmMinute() & 0x7F));
}
} else {
irqLevel(0);
}
}
auto S3511A::readSIO() -> n1 {
return sio | ~rwSelect | ~cs;
}
auto S3511A::writeCS(n1 data) -> void {
n1 csPrev = cs;
cs = data;
//clear command status on falling edge
if(csPrev == 1 && cs == 0) {
inBuffer = 0x00;
shift = 0;
index = 0;
rwSelect = 0;
cmdLatched = 0;
}
}
auto S3511A::writeSIO(n1 data) -> void {
sio = data;
}
auto S3511A::writeSCK(n1 data) -> void {
n1 sckPrev = sck | ~cs;
sck = data;
//only read SIO data if CS is raised
if(!cs) return;
//process command and output data on falling edge of SCK
if(sckPrev == 1 && sck == 0) {
if(!cmdLatched && shift == 0) writeCommand();
if(cmdLatched && rwSelect == 1 && shift == 0) readRegister();
sio = outBuffer.bit(shift);
}
//sample RTC command data on rising edge of SCK
if(sckPrev == 0 && sck == 1) {
//add bit into input buffer
inBuffer.bit(shift) = sio;
shift++;
if(cmdLatched && rwSelect == 0 && shift == 0) writeRegister();
}
}
auto S3511A::writeCommand() -> void {
n4 magic = inBuffer >> 4;
n4 cmd = inBuffer;
if(magic != 0b0110) {
//flip bit order of command
magic = cmd;
cmd.bit(0) = inBuffer.bit(7);
cmd.bit(1) = inBuffer.bit(6);
cmd.bit(2) = inBuffer.bit(5);
cmd.bit(3) = inBuffer.bit(4);
}
if(magic != 0b0110) return; //invalid command
rwSelect = cmd;
regSelect = cmd >> 1;
cmdLatched = 1;
//process any registers that have an effect on write without a payload
if(rwSelect == 1) return;
switch(regSelect) {
case 0:
//RESET
initRegs(true);
break;
default:
break;
}
}
auto S3511A::readRegister() -> void {
switch(regSelect) {
case 1:
//STATUS
outBuffer = status();
break;
case 2: {
//DATETIME
switch(index) {
case 0: outBuffer = year(); index++; break;
case 1: outBuffer = month(); index++; break;
case 2: outBuffer = day(); index++; break;
case 3: outBuffer = weekday(); index++; break;
case 4: outBuffer = hour(); index++; break;
case 5: outBuffer = minute(); index++; break;
default: outBuffer = second(); break;
}
break;
}
case 3: {
//TIME
switch(index) {
case 0: outBuffer = hour(); index++; break;
case 1: outBuffer = minute(); index++; break;
default: outBuffer = second(); break;
}
break;
}
case 4: {
//ALARM
switch(index) {
case 0: outBuffer = alarmHour(); index++; break;
default: outBuffer = alarmMinute(); break;
}
}
default:
outBuffer = 0xff;
break;
}
}
auto S3511A::writeRegister() -> void {
switch(regSelect) {
case 1:
//STATUS
status().bit(1) = inBuffer.bit(1);
status().bit(3) = inBuffer.bit(3);
status().bit(5) = inBuffer.bit(5);
status().bit(6) = inBuffer.bit(6);
status().bit(7) &= inBuffer.bit(7);
break;
case 2: {
//DATETIME
switch(index) {
case 0: year() = inBuffer; index++; break;
case 1: month() = inBuffer; index++; break;
case 2: day() = inBuffer; index++; break;
case 3: weekday() = inBuffer; index++; break;
case 4: hour() = inBuffer; index++; break;
case 5: minute() = inBuffer; index++; break;
default: second().bit(0,6) = inBuffer.bit(0,6); break;
}
break;
}
case 3: {
//TIME
switch(index) {
case 0: hour() = inBuffer; index++; break;
case 1: minute() = inBuffer; index++; break;
default: second().bit(0,6) = inBuffer.bit(0,6); break;
}
break;
}
case 4: {
//ALARM
switch(index) {
case 0: alarmHour() = inBuffer; index++; break;
default: alarmMinute() = inBuffer; break;
}
}
default:
break;
}
}
auto S3511A::initRegs(bool reset) -> void {
year() = 0;
month() = 1;
day() = 1;
weekday() = 0;
hour() = 0;
minute() = 0;
second() = 0;
status() = reset ? 0x00 : 0x82;
alarmHour() = 0x00;
alarmMinute() = reset ? 0x00 : 0x80;
}
}
+64
View File
@@ -0,0 +1,64 @@
#pragma once
namespace ares {
//Seiko S-3511A Real-Time Clock
struct S3511A {
// bytes 0- 6: date/time data, BCD
// bytes 7- 7: status register
// bytes 8-15: last timestamp
// bytes 16-17: alarm register
static constexpr u32 size = 18;
n8 data[size];
virtual auto irqLevel(bool value) -> void = 0;
//s3511a.cpp
auto load() -> void;
auto save() -> void;
auto power() -> void;
auto tickSecond() -> void;
auto checkAlarm() -> void;
auto readSIO() -> n1;
auto writeCS(n1 data) -> void;
auto writeSIO(n1 data) -> void;
auto writeSCK(n1 data) -> void;
auto writeCommand() -> void;
auto readRegister() -> void;
auto writeRegister() -> void;
auto initRegs(bool reset) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
//pin states
n1 cs;
n1 sio;
n1 sck;
//buffered command data
n8 inBuffer;
n8 outBuffer;
n3 shift;
n3 index;
//internal state
n1 rwSelect;
n3 regSelect;
n1 cmdLatched;
n15 counter;
auto year() -> n8& { return data[ 0]; }
auto month() -> n8& { return data[ 1]; }
auto day() -> n8& { return data[ 2]; }
auto weekday() -> n8& { return data[ 3]; }
auto hour() -> n8& { return data[ 4]; }
auto minute() -> n8& { return data[ 5]; }
auto second() -> n8& { return data[ 6]; }
auto status() -> n8& { return data[ 7]; }
auto alarmHour() -> n8& { return data[16]; }
auto alarmMinute() -> n8& { return data[17]; }
};
}
@@ -0,0 +1,15 @@
auto S3511A::serialize(serializer& s) -> void {
s(array_span<u8>{data, size});
s(cs);
s(sio);
s(sck);
s(inBuffer);
s(outBuffer);
s(shift);
s(index);
s(rwSelect);
s(regSelect);
s(cmdLatched);
s(counter);
}
+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
)
-17
View File
@@ -1,17 +0,0 @@
ares.components += z80
ares.components += tms9918
ares.components += sn76489
ares.objects += ares-cv-cpu
ares.objects += ares-cv-vdp
ares.objects += ares-cv-psg
ares.objects += ares-cv-system
ares.objects += ares-cv-cartridge
ares.objects += ares-cv-controller
$(object.path)/ares-cv-cpu.o: $(ares.path)/cv/cpu/cpu.cpp
$(object.path)/ares-cv-vdp.o: $(ares.path)/cv/vdp/vdp.cpp
$(object.path)/ares-cv-psg.o: $(ares.path)/cv/psg/psg.cpp
$(object.path)/ares-cv-system.o: $(ares.path)/cv/system/system.cpp
$(object.path)/ares-cv-cartridge.o: $(ares.path)/cv/cartridge/cartridge.cpp
$(object.path)/ares-cv-controller.o: $(ares.path)/cv/controller/controller.cpp
+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>
+1
View File
@@ -56,6 +56,7 @@ auto System::load(Node::System& root, string name) -> bool {
}
node = Node::System::create(information.name);
node->setAttribute("configuration", name);
node->setGame({&System::game, this});
node->setRun({&System::run, this});
node->setPower({&System::power, this});
+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
)
-23
View File
@@ -1,23 +0,0 @@
ares.components += mos6502
ares.components += ym2149
ares.components += ym2413
ares.components += m24c
ares.components += sst39sf0x0
ares.objects += ares-fc-system
ares.objects += ares-fc-controller
ares.objects += ares-fc-expansion
ares.objects += ares-fc-cartridge
ares.objects += ares-fc-cpu
ares.objects += ares-fc-apu
ares.objects += ares-fc-ppu
ares.objects += ares-fc-fds
$(object.path)/ares-fc-system.o: $(ares.path)/fc/system/system.cpp
$(object.path)/ares-fc-controller.o: $(ares.path)/fc/controller/controller.cpp
$(object.path)/ares-fc-expansion.o: $(ares.path)/fc/expansion/expansion.cpp
$(object.path)/ares-fc-cartridge.o: $(ares.path)/fc/cartridge/cartridge.cpp
$(object.path)/ares-fc-cpu.o: $(ares.path)/fc/cpu/cpu.cpp
$(object.path)/ares-fc-apu.o: $(ares.path)/fc/apu/apu.cpp
$(object.path)/ares-fc-ppu.o: $(ares.path)/fc/ppu/ppu.cpp
$(object.path)/ares-fc-fds.o: $(ares.path)/fc/fds/fds.cpp
+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;
+2
View File
@@ -61,6 +61,7 @@ auto System::load(Node::System& root, string name) -> bool {
}
node = Node::System::create(information.name);
node->setAttribute("configuration", name);
node->setGame({&System::game, this});
node->setRun({&System::run, this});
node->setPower({&System::power, this});
@@ -85,6 +86,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
)
-16
View File
@@ -1,16 +0,0 @@
ares.components += sm83
ares.components += m93lcx6
ares.objects += ares-gb-system
ares.objects += ares-gb-bus
ares.objects += ares-gb-cartridge
ares.objects += ares-gb-cpu
ares.objects += ares-gb-ppu
ares.objects += ares-gb-apu
$(object.path)/ares-gb-system.o: $(ares.path)/gb/system/system.cpp
$(object.path)/ares-gb-cartridge.o: $(ares.path)/gb/cartridge/cartridge.cpp
$(object.path)/ares-gb-bus.o: $(ares.path)/gb/bus/bus.cpp
$(object.path)/ares-gb-cpu.o: $(ares.path)/gb/cpu/cpu.cpp
$(object.path)/ares-gb-ppu.o: $(ares.path)/gb/ppu/ppu.cpp
$(object.path)/ares-gb-apu.o: $(ares.path)/gb/apu/apu.cpp
+4
View File
@@ -44,6 +44,7 @@ struct APU : Thread {
n11 frequency;
bool counter;
n4 sample;
i16 output;
bool dutyOutput;
n3 phase;
@@ -77,6 +78,7 @@ struct APU : Thread {
n11 frequency;
bool counter;
n4 sample;
i16 output;
bool dutyOutput;
n3 phase;
@@ -105,6 +107,7 @@ struct APU : Thread {
bool counter;
n8 pattern[16];
n4 sample;
i16 output;
u32 length;
u32 period;
@@ -135,6 +138,7 @@ struct APU : Thread {
n3 divisor;
bool counter;
n4 sample;
i16 output;
u32 length;
n3 envelopePeriod;
+16
View File
@@ -1,4 +1,20 @@
auto APU::readIO(u32 cycle, n16 address, n8 data) -> n8 {
if(Model::GameBoyColor()) {
//PCM12
if(address == 0xff76 && cycle == 2) {
data.bit(0,3) = square1.sample;
data.bit(4,7) = square2.sample;
return data;
}
//PCM34
if(address == 0xff77 && cycle == 2) {
data.bit(0,3) = wave.sample;
data.bit(4,7) = noise.sample;
return data;
}
}
if(address < 0xff10 || address > 0xff3f) return data;
//NR10
+2 -1
View File
@@ -16,7 +16,7 @@ auto APU::Noise::run() -> void {
}
}
n4 sample = lfsr & 1 ? 0 : (u32)volume;
sample = lfsr & 1 ? 0 : (u32)volume;
if(!enable) sample = 0;
output = sample;
@@ -79,6 +79,7 @@ auto APU::Noise::serialize(serializer& s) -> void {
s(divisor);
s(counter);
s(sample);
s(output);
s(length);
s(envelopePeriod);
+2 -1
View File
@@ -14,7 +14,7 @@ auto APU::Square1::run() -> void {
}
}
n4 sample = dutyOutput ? (u32)volume : 0;
sample = dutyOutput ? (u32)volume : 0;
if(!enable) sample = 0;
output = sample;
@@ -120,6 +120,7 @@ auto APU::Square1::serialize(serializer& s) -> void {
s(frequency);
s(counter);
s(sample);
s(output);
s(dutyOutput);
s(phase);
+2 -1
View File
@@ -14,7 +14,7 @@ auto APU::Square2::run() -> void {
}
}
n4 sample = dutyOutput ? (u32)volume : 0;
sample = dutyOutput ? (u32)volume : 0;
if(!enable) sample = 0;
output = sample;
@@ -77,6 +77,7 @@ auto APU::Square2::serialize(serializer& s) -> void {
s(frequency);
s(counter);
s(sample);
s(output);
s(dutyOutput);
s(phase);
+2 -1
View File
@@ -12,7 +12,7 @@ auto APU::Wave::run() -> void {
}
static const u32 shift[] = {4, 0, 1, 2}; //0%, 100%, 50%, 25%
n4 sample = patternSample >> shift[volume];
sample = patternSample >> shift[volume];
if(!enable) sample = 0;
output = sample;
@@ -95,6 +95,7 @@ auto APU::Wave::serialize(serializer& s) -> void {
s(counter);
s(pattern);
s(sample);
s(output);
s(length);
s(period);
Loaded 100 of 4883 files, more files were not shown because too many files have changed in this diff. Show more