Fix envelope timing and key-on delay, jump to the repeat address on sample end.
Capture CD audio before volume processing,
Fix sign handling for cd-rom volume and pitch modulation
ref: https://psx-spx.consoledev.net/soundprocessingunitspu/
Devices are now in charge of their own timing, fix Memory Card and Controller timing to be closer to hardware.
Fixes an infinite loop polling for memory cards in Ace Combat 3 (USA)
Clearing DPC_FREEZE calls flushCommands even when END equals CURRENT. Previously, this set pipeBusy and startGclk without executing any commands, leaving an initially idle RDP reporting busy.
Return before setting the busy flags when no forward command range is available. Preserve existing busy state for starved pipelines and leave START/END latching unchanged.
The following are new behavoirs in the python tooling:
Extract DIP switch definitions, input mappings, and other metadata by parsing tables directly from the MAME source tree; this lifts metadata (such as dip switch names and bit-values and button labels) into Arcade.bml, no code is lifted.
Support custom overrides for information that is missing or insufficient in MAME's database.
Allow ROMs to be excluded from the generated database, including incomplete dumps, unsupported bootlegs, and non-game software.
Extend the existing per-system input override functionality to support game-specific controller mappings.
The intended workflow is for users to configure their Virtual Pad once. The Virtual Pad attempts to map inputs to each system's controller based on the physical position of its buttons.
Users can then customize mappings by adding overrides for specific inputs per-system, or per-game. Per-game overrides can only be configured while the relevant game is loaded.
ares attempts to strip common Disc, Disk, Side and Part suffixes from game titles, allowing multi-disc games to share the same input configuration.
Introduce a shared DIP switch implementation for arcade systems, replacing system-specific implementations.
Neo Geo:
Implement the NEC uPD4990A real-time clock.
Implement the MVS hardware watchdog.
Fix IRQ acknowledgement register handling to that only pending IRQs can be acknowledged
Move ROM decryption and protection handling into runtime PCB emulation, more closely reflecting the behaviour of original hardware.
Add support for additional protection schemes and game-specific memory mappers.
SG-1000A:
Add support for the encrypted Z80 variant used by Championship Wrestling.
Introduce separate opcode fetch and data read paths for the Z80, allowing accurate emulation of hardware-dependent decryption.
Portions of the ROM decryption and protection implementations are derived from MAME. Only code distributed under permissive licences, including the BSD 3-Clause License, has been incorporated.
All MAME-derived implementations are explicitly identified in the source code, with the applicable copyright notices and licence terms preserved in the project's LICENSE file.
To measure texture cache timing, textured draws previously waited for
the renderer to catch up before emulation could continue.
Now we wait only when the GPU becomes ready for another draw.
draw timing observed by the game is unaffected.
Moon Patrol's HSCROL write was landing too early in ares, corrupting the mountains
Altirra Hardware Reference Manual was used to determine correct behavoir, which I believe to be trustworthy as the introduction specifies that "This document attempts to describe the hardware in detail as the target to which the emulator aspires to imitate"
Weave (default): combines the current field with the previous field. this preserves detail but may introduce combing during motion. This is how ares behaved historically.
Bob: displays the current field and interpolates missing lines. This prevents motion combing but causes a noticable loss of vertical detail and may flicker thin lines.
Blend: displays an average of consecutive bobbed fields. Behaves similar to bob, but swaps flicker for motion blur.
Phosphor: displays only the currently displaying field while simulating phosphor decay. This Produces a darker image with visible scanlines and may flicker, but is closer to how a real CRT handles interlaced video.
nocash DIAG's hardware cache tests measure miss penalties of ~60 CPU
clocks for eight entries and ~120 clocks for sixteen entries. This is
approximately 12 GPU clocks per 8-byte refill.
We use 13 clocks here as it better fits JaCzekanski's GPU bandwidth
test; textured drawing timings now measure within ~1-2% of the hardware
baseline.
- prevent discarded polygons from counting in draw timing calculations
- fix depth mode changes applying one frame too late
- fix cd-rom stop command
- prevent MDEC output fifo from losing data when full and reduce output size to a more realistic 32 words-
Rationale is that the clang64 ci is resulting in a build that drops as low as 40vps in FMV sequences in the PS1 core, vs 90vps in the same scene for clang-cl
Pinning a known-performant version of clang was considered (local testing proved clang22 produces more performant builds than clang20), but this is not viable with how msys2 is managed. Investigation concluded that we cannot reliably update the clang msys environment; just running 'update:true' breaks the build due to a ymfm issue with the clang23 runtime, and installing the 'clang22' packages still uses the clang23 runtimes, it only pins the compiler itself.
A block can end before an instruction that has a gdb breakpoint. Its
last instruction can then be straight-line code, which does not commit
the pipeline PC. The block exited with ipu.pc at the last commit point,
so the CPU ran the instructions after that point a second time. If that
point was an internal entry of the same block, the CPU looped forever
and the breakpoint never hit.
Commit the pipeline PC on the last instruction of every block. All other
block ends already commit there, so code without breakpoints is
unchanged.
- more accurately model the CPU bus, write buffering and cache behavior
- improve DMA arbitration, chopping, transfer timing, and interaction with CPU
- rework CD-ROM command timing, deferred responses, interrupts, sector delivery, subchannel data, and disc session handling
- implement the GPU command FIFO, busy timing, texture caches, rasterization, and improve scanout accuracy
- improve timer synchronization, reset, interrupt, and blanking behavior
- improve peripheral, SPU, MDEC, and memory-mapped I/O timing
- add support for Datel Action Replay and Blaze Xplorer cartridges
- add support for the Pixel Accuracy toggle to enable per-pixel scanout (required by tajmiing demo)
These changes were validated against psxtest_cpx, psxtest_gpu, nocash diag.exe, JaCzekanski's tests, and the pcsx-redux CD-ROM torture tests.
Most of tests now pass, and known problematic games such as Monkey Hero are working.
Framebuffer output matches expected hardware output pixel-for-pixel in the nocash diagnostics and psxtest_gpu primitive tests.
Timer test results generally remain within a small margin of hardware baseline results (when compared against the psx.log reference point shipped with the tests)
psxtest_cpx and psxtest_gpu do not initialize controllers correctly when launched directly from the BIOS. You must run them them through software that initializes the hardware first, such as a Datel Action Replay or Blaze Xplorer cartridge. These devices can be configured in Core settings. This issue exists on real hardware and is correct behavoir.
ares can now run the tajmiing demo and all its effects end-to-end.
tajmiing changes display registers at individual-pixel boundaries, so it requires the Pixel Accuracy option in Video settings. Scanline-level synchronization remains the default as oridnary software does not depend on mid-scanline register changes.
Latch the left and right edge matches independently until the next scanline, preserving the inclusive right edge. This prevents mid-line bounds writes from reopening a stopped window, as demonstrated by Mickey Magic and MiSTer SNES PR #508.
Serialize the latches and bump the SNES state format. Fixesares-emulator/ares#2645.
With FreeBSD 15.0 going EOL very soon, it is time to update the runner
in the CI to FreeBSD 15.1. This version is supported by Cross-Platform
GitHub Actions since version 1.3.0, and the runner is updated to the
currently newest version 1.6.0, which corresponds to the commit
https://github.com/cross-platform-actions/action/commit/e0b9770014ba65d5e0815f15b74031c3a635f641.
Using the operating system's shell for running commands inside steps is
deprecated. Cross-Platform GitHub Actions provides and recommends the
new custom shell cpa.sh instead, which the runner is now using.
This requires to split the "Build: FreeBSD" step into at least one
separate step for setting up the VM before executing commands in the
following steps. This opens up the opportunity to be more in line with
the Linux runner by installing the build dependencies in its own step,
"Install FreeBSD Dependencies".
Before installing dependencies, the runner now updates the preinstalled
packages in the VM via pkg upgrade -y. This ensures that the whole VM is
cohesively up-to-date.
Last but not least, the TARGET_PRESET environment variable must be set
in the "Build: FreeBSD" step with the --environment-variables option of
cpa.sh, or else it won't be propagated to the build environment.
Ported directly from bsnes PRs 377 and 401.
- When triggering a cache preload by writing to $7f48, update the pb register with the prepared program page
- When preloading a page, ignore all runtime checks and reload the page immediately
- Step 1+WS on both reads for cache, not just one
- Remove extra cycle on bus reads/writes
- Remove extra cycle on DMA to internal RAM (fixes excessive slowdown in Morph Moth fight)
On macoS, a binary executed directly by another process (e.g. a frontend
spawning and emulator) starts as an unregistered background process. It
must be promoted to a regular GUI application to reclaim focus.
Generic port menu callbacks could mutate scheduler threads and audio streams while the emulator worker was active. Route both disconnect and connect actions through one Program::Guard-protected helper and add a deterministic concurrent regression test.
The CPU keeps a free-running cycle counter (COUNT) that guest software
reads to measure elapsed time. Internally the emulator does not update
that counter after every instruction: cycles are accumulated in a
running clock and only folded into COUNT when the CPU synchronizes with
the rest of the machine. Reading the register returned the folded value
only, ignoring any cycles accumulated since the last fold, so the value
handed back to software could be stale.
How stale depends on how often synchronization happens, which is why
this was mostly invisible with the interpreter and clearly wrong with
the recompiler. The interpreter synchronizes after every instruction, so
at most one instruction worth of cycles was missing. The recompiler
translates a whole run of instructions into a single unit of host code
and only folds the accumulated cycles at its boundaries, so several
consecutive reads of COUNT inside one such unit all returned the exact
same number. Code that reads the counter repeatedly to check that time
is moving forward would see it standing still; the test_timer_ticks test
in the libdragon test suite fails this way, with two successive readings
comparing equal.
Track how many cycles have already been folded into COUNT in a separate
countClock field, so the cycles accumulated since then can be recovered
at any point. Reading COUNT now folds those pending cycles in first,
which both returns an up-to-date value and evaluates the COMPARE match
at the same moment, keeping the register and the timer interrupt
consistent with each other. Writing COUNT or COMPARE folds them in as
well, so the pending cycles are attributed to the old value rather than
being added on top of the newly written one.
The CPU has a free-running cycle counter (COUNT) and a programmable
target register (COMPARE); an interrupt is raised whenever the counter
reaches the target. The check for that event was written as
"count < compare && count + elapsed >= compare", which assumes the
target always lies ahead of the current counter value in plain
arithmetic order. Since both registers are unsigned, that assumption
breaks as soon as the target is behind the counter, and it breaks
permanently when the target is exactly zero: no unsigned value is ever
less than zero, so the first half of the condition is never true and the
interrupt is never raised at all.
That is not a corner case in practice. The counter is only 32 bits wide
and wraps around roughly every 90 seconds, so software that wants to
maintain a wider timestamp typically arms the target at zero in order to
be notified on every wrap. libdragon did exactly this: timer_init()
programs COMPARE to zero and used the resulting interrupt to increment
the high half of a 64-bit tick counter. Under ares that interrupt never
arrived, so the high half was never incremented and timer_ticks() went
backwards across a wrap, which is what the test_timer_ticks test in the
libdragon test suite reports.
Replace the ordered comparison with a modular distance computed over the
counter's full range: the number of ticks remaining until the target is
(compare - count) truncated to the counter width, and the interrupt
fires when at least that many ticks elapse. This behaves identically
when the target is ahead of the counter and additionally handles the
wrap-around case, including a target of zero. The counter update, the
crossing check and the cycle profiling counters are moved together into
a new stepCount() helper so that a single implementation stays
authoritative.
The client can now ask the stub to deliver chosen signals without stopping
or reporting (gdb sends QPassSignals automatically for signals configured
'handle <sig> nostop noprint pass'). Advertised in qSupported; the pass set
is client state, cleared on connect/disconnect like breakpoints.
## Overview
Adds Nintendo Vs. UniSystem support to the ares FC core. Games remain in
MAME
ZIP format and load through the existing Arcade path, without going
through
the iNES detection path used by regular Famicom software.
The implementation covers MAME metadata generation, parent ZIP lookup,
Vs. PPU
and palette behavior, cartridge boards, protection logic, cabinet I/O,
DIP
switches, controller wiring, Zapper input, and save states. A total of
41 Vs.
UniSystem sets have been validated. Vs. DualSystem, non-standard bootleg
hardware, and other configurations that have not yet been implemented
are
explicitly marked as unsupported instead of being started with the
UniSystem
model.
## Why `vsnes.py` is separate
MAME groups three substantially different hardware families in
`nintendo/vsnes.cpp`:
- Vs. UniSystem with one CPU and one PPU;
- Vs. DualSystem with two CPUs and two PPUs;
- non-standard bootleg hardware built around a Z80 and SN76489.
The generic MAME parser reads common data such as machine entries, ROM
regions,
and DIP switches. Those fields alone are not enough to determine which
Vs.
hardware model a game requires. The three families have different
runtime
structures and cannot share a single emulation path.
Configurations also differ between Vs. UniSystem games. The PPU,
palette,
cartridge board, protection logic, controller wiring, Zapper support,
and DIP
settings may all vary by set. The core needs explicit configuration data
rather than inferring hardware from a game title.
`vsnes.py` reuses the MAME XML and ROM-region information produced by
the
generic parser, then adds hardware classification and per-game
configuration.
It generates a deterministic `VsSystem.bml` database. At runtime,
supported
sets select the corresponding FC hardware model from this metadata,
while
DualSystem and bootleg sets are rejected with a clear explanation.
## Video
The combined video shows the attract modes of all 41 supported games.
Each
game is shown for approximately ten seconds, with its name in the
upper-right corner.
https://github.com/user-attachments/assets/46a59b2b-f64a-40ce-a870-1351d5df3948https://github.com/user-attachments/assets/7927d1d0-4349-4f4b-9092-feeb7b0ac127https://github.com/user-attachments/assets/d162c834-b227-497b-afe7-2f766f3ab42ahttps://github.com/user-attachments/assets/12d7b58e-7cd5-4bbf-b040-9d615e654e0chttps://github.com/user-attachments/assets/a8708059-4369-48e1-be1f-42d15099d7a8
## Screenshots
The contact sheet contains one attract-mode screenshot for each game,
composed
at the original capture resolution.
<img width="3920" height="5328" alt="contact-sheet"
src="https://github.com/user-attachments/assets/e111cf05-4a49-4b0d-9719-082b2b925342"
/>
## Supported sets
The following 41 Vs. UniSystem MAME sets have been validated for loading
and
attract-mode operation:
| No. | MAME short name | Game |
| ---: | --- | --- |
| 1 | `btlecity` | Vs. Battle City |
| 2 | `cluclu` | Vs. Clu Clu Land |
| 3 | `cstlevna` | Vs. Castlevania |
| 4 | `drmario` | Vs. Dr. Mario |
| 5 | `duckhunt` | Vs. Duck Hunt (set DH3 E) |
| 6 | `excitebk` | Vs. Excitebike (set EB4-3 E) |
| 7 | `excitebkj` | Vs. Excitebike (set EB4-4 A) |
| 8 | `excitebko` | Vs. Excitebike (set EB4-3 ?) |
| 9 | `goonies` | Vs. The Goonies (set E) |
| 10 | `hogalley` | Vs. Hogan's Alley (set HA4-1 E-1) |
| 11 | `iceclimb` | Vs. Ice Climber (set IC4-4 B-1) |
| 12 | `iceclimba` | Vs. Ice Climber (set IC4-4 ?) |
| 13 | `jajamaru` | Vs. Ninja Jajamaru Kun (Japan) |
| 14 | `ladygolf` | Vs. Stroke & Match Golf (Ladies Version, set LG4 ?)
|
| 15 | `ladygolfe` | Vs. Stroke & Match Golf (Ladies Version, set LG4 E)
|
| 16 | `nvs_machrider` | Vs. Mach Rider (Endurance Course Version) |
| 17 | `nvs_machridera` | Vs. Mach Rider (Fighting Course Version, set
MR4-1 A) |
| 18 | `nvs_mightybj` | Vs. Mighty Bomb Jack (Japan) |
| 19 | `nvs_platoon` | Vs. Platoon |
| 20 | `rbibb` | Vs. Atari R.B.I. Baseball (set 1) |
| 21 | `rbibba` | Vs. Atari R.B.I. Baseball (set 2) |
| 22 | `skatekds` | Vs. Skate Kids. (Graphic hack of Super Mario Bros.)
|
| 23 | `smgolf` | Vs. Stroke & Match Golf (Men Version, set GF4-2 F) |
| 24 | `smgolfb` | Vs. Stroke & Match Golf (Men Version, set GF4-2 ?) |
| 25 | `smgolfj` | Vs. Stroke & Match Golf (Men Version) (Japan, set GF3
B) |
| 26 | `starlstr` | Vs. Star Luster |
| 27 | `suprmrio` | Vs. Super Mario Bros. (set SM4-4 E) |
| 28 | `suprmrioa` | Vs. Super Mario Bros. (set ?, harder) |
| 29 | `supxevs` | Vs. Super Xevious |
| 30 | `tkoboxng` | Vs. T.K.O. Boxing |
| 31 | `topgun` | Vs. Top Gun |
| 32 | `vsfdf` | Vs. Freedom Force |
| 33 | `vsgradus` | Vs. Gradius (US, set GR E) |
| 34 | `vsgshoe` | Vs. Gumshoe (set GM5) |
| 35 | `vspinbal` | Vs. Pinball (US, set PN4 E-1) |
| 36 | `vspinbalj` | Vs. Pinball (Japan, set PN3 B) |
| 37 | `vsskykid` | Vs. Super SkyKid |
| 38 | `vsslalom` | Vs. Slalom |
| 39 | `vssoccer` | Vs. Soccer (set SC4-2 A) |
| 40 | `vssoccera` | Vs. Soccer (set SC4-3 ?) |
| 41 | `vstetris` | Vs. Tetris |
## Changes
- Accumulate relative mouse movement until it is read and consumed by an
input mapping.
- Maintain an independent read position for each `InputRelative`
binding.
- Synchronize relative input positions when input bindings or mouse
capture state changes.
- Apply the same relative-motion handling to the Raw Input, NSEvent, and
Xlib mouse drivers.
## Motivation
In my testing, `InputManager::poll()` is called approximately once every
8ms on my system, with observed intervals generally no shorter than 5ms.
At 60Hz, each frame lasts approximately 16.67ms, so input is normally
polled twice per frame.
Each poll retrieves the mouse-axis movement accumulated during the
preceding approximately 8ms. However, emulator cores generally read
relative input only once per frame. This means that `InputManager` may
complete its second poll before the core reads the movement value.
The previous implementation retained only the mouse-axis movement
reported by the most recent poll. The second poll therefore overwrote
the result of the first, allowing the core to observe only the movement
from the latest approximately 8ms. Mouse movement from the earlier
approximately 8ms of the frame was lost.
This change accumulates all relative mouse movement produced between
consecutive core input reads. As a result, even when
`InputManager::poll()` runs multiple times within a single frame, the
core can still retrieve the complete mouse-axis movement accumulated
during that period.
## Abstract
Support the absolute mouse movement events in the native input driver
for Windows.
Modifications:
- Convert the absolute original input coordinates to relative motion
increments;
- Handle the coordinate spaces of the main desktop and virtual desktop
while maintaining independent absolute coordinate positions;
- Add locking in the `poll` function to prevent partial data loss in the
event of multi-threaded competition.
## Reasons
When I used 'Windows Remote Desktop Connection' for remote debugging, I
found that 'win raw input' did not provide the corresponding 'relative
mouse event'. Since 'ruby' ignored the 'absolute mouse event', the input
relying on the mouse (such as the crosshair of a gun sight) could
receive key operations, but it was unable to move.
Fixes a video mixing issue which affected graphics in the "Demon's
Judgement" LDRom2 game for the Pioneer LaserActive with the NEC PAC.
---------
Co-authored-by: Roger Sanders <[email protected]>
This uses all the latest research on the exact behavior of flash chips,
including quirks of specific models, as documented on n64brew.
Thanks to the new PI bus emulation, it is now possible to correctly
implement many quirks "naturally", because of the simple way flash
chips interact with the bus.
PIDevice is now a generic device sitting on the PI bus that is able
to reply to addresses in any range. Now each device knows the addresses
it is listening to, which is how the hardware works.
PI accesses are only 16-bit wide, and both DMA and CPU I/O are built
upon it. There is no more code to mimic the weird access patterns for
misaligned addresses or different access sizes, as everything descends
naturally from the way the bus works (as it should be).
Open bus is simulated by latching the last value on the bus, which is
what happens on hardware.
This opens the door to more accurate emulation of chips which abuse the
bus in weird ways (like flash memories).
We always update hidden bits on memory writes. Given that in most cases
this is done during dcache flushes, we use SIMD to optimize that code
path and update a whole cacheline's worth with a few opcodes.
Also take the chance to add a mi/bus.hpp that implements the special
MI modes (ebus, repeat, upper), so that they naturally only apply
to CPU-issued reads.
This finally allows Ares to fully run through the IPL3 to fully initialize
the RAM chips. It tries to simulate also all the various non-working
conditions so that a change in a IPL3 that results in failure to boot,
should also fail in Ares. Obviously this would be a very long journey,
but at least all major failures are covered here.
Default RDRAM linear mapping is still kept as default as a fast path
in the recompiler to avoid slowdowns in normal situations. Given
that parallel-RDP doesn't support non-linear mappings, we just emit
a warning in that case.
Invalid current values will result in degraded RAM accesses like on real
hardware. This is also necessary to fully pass the current calibration
algorithm and to provide entropy (collected by libdragon's IPL3).
If we hit the final branch of the if in the read hook and `byteCount` is
not a multiple of 4, the remaining bytes are never read, but the buffer
is still sent back with unset data. This adds one more iteration to the
loop if necessary to read another word, and then shrinks the string to
the correct size.
In the write hook, the simple cases will do a write and then break the
switch and end up in the conditionals, potentially writing twice. So I
switched the breaks to returns.
The final conditional code in the write hook also cannot handle data
sizes that aren't multiples of 4 bytes, but I'm less confident about how
to fix that. Happy to add it to this PR if someone who knows what
they're doing advises.
Also trimmed some trailing whitespace.
Before we were drawing the frame according to the VI registers at line
0. After a recent change (I believe
https://github.com/ares-emulator/ares/commit/31526ded9196b046b0b5ce1769f14335eba9cc33
), we now draw it according to VI registers when display area begins.
This means that we take into account the vblank interrupt that normally
changes the registers so the field swapping workaround is not needed
anymore.
Some platforms experienced very poor performance with the SDL3 audio
driver, especially in combination with a demanding core like the N64.
It is assumed that SDL couldn't keep up filling the output device buffer
with the audio data from the input queue buffer. Increasing the amount
of generated input data before feeding it to the device buffer has shown
to greatly improve the performance.
This sparked the following idea and change to how the SDL3 audio driver
fills its buffers: request a fixed-sized 10ms device buffer and apply
the latency to the input buffer, i.e. the input buffer holds a multiple
of 10ms worth of audio. This allows SDL to steadily consume audio from
the input buffer and feed it into the 10ms device buffer, while the user
can still control the latency.
Additionally add the value 30 to the possible latency options. This
allows users to specify a lower latency than 40 if 20 is just a tiny bit
shy of being good enough.
The renderSettingsLabel identifier isn't declared anymore after the
recent structural changes, but it's still referenced conditionally in
desktop-ui/settings/cores.cpp and breaks the build if the N64 core is
disabled:
/tmp/ares/desktop-ui/settings/cores.cpp:108:3: error: use of undeclared identifier 'renderSettingsLabel'
108 | renderSettingsLabel.setCollapsible(true).setVisible(false);
| ^
Remove it to fix the build.
Remove the build dependencies of the removed audio and input drivers,
now that SDL3 is the only supported driver.
Additional cleanup on FreeBSD:
- libX* and libglvnd are dependencies of sdl3 itself and can reasonable
be expected to continue to be so. This allows to remove them from the
list of explicit bulid dependencies.
- vulkan-loader provides libvulkan.so which is a dlopen'ed runtime
dependency of parallel-rdp used in the N64 core. It is not a build
dependency and can be removed (though it gets installed anyway as a
dependency of sdl3).
We were telling Vulkan to display a frame as per the VI configuration
at vblank (line 0). This is wrong since all games will actually use
vblank to configure VI for the new frame. Vulkan would thus draw the
*previous* frame, rather than the new one that was just created, causing
one full frame of latency. The correct point where to kick Vulkan is at
vstart, when the active display begins.
With CPU-based rendering in a double-buffering scenario (rather than
triple buffering), this means that the wrong framebuffer would always
be shown: the one that was just going to be drawn upon. Thus, we would
basically get a race between the emulated CPU writing to RDRAM and the
host Vulkan reading RDRAM.
The bug was hidden when using RDP rendering because RDP emulation also
goes through Vulkan, so it would basically be queued *after* the VI
drawing rather than *during* it.
Use the application stream format rather than the physical device format.
Some outputs, such as HDMI/TV devices with Dolby processing enabled,
may expose a multichannel device format even though ares is submitting
stereo float audio to SDL. Using the device format for queue sizing and
drain timing could make the blocking sync path sleep for the wrong
amount of time, causing the emulator to run too slowly.
General cleanup:
- avoid heap allocation for every audio packet
- add proper failure checks
- correctly teardown SDL_Audio on shutdown
Replace the old fixed multiplier window sizing model with configurable
viewport sizing.
Window sizes are now stored as target viewport dimensions rather than
being derived from the emulated screen. Standard presets have been
provided, as well as the option to specify a custom size.
Adaptive sizing has been reworked to treat the window size as target
bounds, the actual window will dynamically grow or shrink within this
boundary to preserve the correct aspect ratio.
Oversized window recovery has been changed to respect aspect ratio
and available workspace rather than a hardcoded reducton from the
monitors geometry.
Add an optional stable text identifier to HID devices and use it for
persisted input mappings when available.
SDL joypads now expose a GUID/slot identifier, so newly saved controller
mappings no longer depend on SDL serial or device path values that can
change across disconnects, reconnects, or app launches. This keeps
multiplayer controllers distinguishable by assigning slots per matching
GUID while avoiding unstable path-derived IDs.
The input mapping parser remains backward compatible with existing
numeric 0x<deviceID>/<group>/<input> mappings. Drivers that do not set a
stable identifier continue to save and load mappings using the existing
numeric HID device ID format.
Uncovered by new tests in n64-systemtest. The JIT wasn't tested because
little-endian is only supported in user-mode for now (RE=1), where
memory accesses must go through TLBs so they currently are not JIT'd.
Anyway the fix should be correct if we eventually uncover full
little-endian mode (with BE=0).
This is a mode available only in the user mode, activated when RE=0. It
facilitates running MIPS binary code that was build for a little-endian
architecture, assuming that the code/data was 8-byte swapped in memory
before running it.
It passes the new RE tests in n64-systemtest
Avoid keeping the dirty-byte mask live across store fast paths in
jitMemoryOpcode. Compute it at the end from Rs+i16 so temporary
register clobbers (eg. SDC1/SWL/SWR) cannot corrupt dirty tracking and
lead to stale cache data.
Terminals are now only hard jumps and the special opcodes that change
state key, timers, etc.
Internal branch targets in each block are also registered as JIT
entrypoints.
Opportunistic branch linking is now removed as not useful anymore.
While provably useful, the implementation is completely confusing. We
need to rework it from scratch at some point. The way it is written
now, it impedes further progress in other areas.
Emit loads and stores directly against fpu state via sreg(2), using the same
full- versus half-mode register layout as the interpreter (word selection and
pairing). COProcessor-unusable blocks still call the C++ helpers. Skip GPR
writes when MFC1/DMFC1 targets $zero. FPU word offsets use CPU::r64 in offsetof
to avoid colliding with the host Real type at file scope.
Add generic LMUL and DIVMOD helpers (32/64, signed/unsigned) and emit fast paths for MULT/MULTU, DIV/DIVU, DMULT/DMULTU, DDIV/DDIVU. Reserved-instruction and divide-by-zero cases stay on interpreter slow paths; DDIV avoids host INT64_MIN/-1 idiv overflow. Decoder no longer marks these opcodes as JitUseCallf or JitAddsExtraCyclesInternally.
Move callf synchronization to the paths that actually emit helper calls, and keep slow-path callf state restoration explicit. Rename jitMayCallf to jitUseCallf so the flag name matches its eager-call semantics.
Route opcode helper calls through a shared setup path that materializes PC and flushes deferred state on demand, so callf overhead is emitted where calls actually occur.
Move trap exception cases to deferred slow paths and generate direct JIT code for the remaining 64-bit shift immediates, keeping reserved-instruction handling and R0 writeback behavior on the fast path.
Expand CPU JIT codegen for DADDIU, DSLLV/DSRLV/DSRAV, DADDU, DSUB, and DSUBU while preserving exact overflow and reserved-instruction behavior through helper fallbacks. Factor 64-bit reserved-instruction gating into a shared helper and collapse duplicated slow-path conditions to keep hot paths compact.
Move ADD/ADDI/DADD/DADDI hot paths to direct codegen with deferred slow-path helpers so overflow and reserved-instruction behavior stay exact without polluting the hot block body. Centralize state-key bit semantics in a typed accessor wrapper so JIT-time folding no longer depends on hardcoded bit masks.
Emit state test/update and endblock jumps only when branch/helper pipeline semantics are active, removing these control-flow overhead ops from the linear hot path.
Accumulate linear nextpc advances and flush only when current PC is needed, removing per-opcode nextpc materialization on the fast path. Also rematerialize helper call PC directly from vaddr in the linear non-delay-slot case.
Commit architectural PC only for branch/helper/terminal paths while preserving exception PC correctness for helper calls and delay slots. This removes unconditional per-opcode ipu.pc stores on the linear hot path.
Keep pipeline pc writes on branch/helper paths, and commit linear opcode ipu.pc from nextpc-4 to reduce per-opcode JIT overhead while preserving n64-systemtest behavior.
Skip per-opcode deferred-cycle flushes for straight-line instructions while keeping EndBlock checks unchanged, reducing hot-loop helper-call overhead without regressing system tests.
Skip emitting EndBlock test/jump in straight-line instructions where state cannot request block termination, reducing hot-loop overhead while preserving control-flow correctness.
Drop JIT metrics counters and reporting from the CPU recompiler to keep the hot-path code easier to read while preserving runtime behavior. This also keeps the architectural state commit path in emit() minimal by removing duplicated commit emission.
Model taken and not-taken link edges per block so conditional branches can be linked by final PC, and add finer diagnostics for no-direct-link causes. Also inline BC1 JIT branch handling with deterministic cause clearing layout checks to reduce unsupported FPU branch cases without regressing exception behavior.
Link JIT blocks lazily within sections with state-key matching and pending backpatches to cut dispatcher overhead. Gate linked jumps on dirty sections, clock/queue budget checks, and unsafe delay slots while adding detailed diagnostics on link misses and candidate coverage.
Convert all remaining integer branch and branch-likely opcodes to direct JIT emission and update decoder JIT flags, while intentionally keeping BC1 on the callf path.
Convert BGTZ, JR, BLTZ, and BGEZ to direct JIT branch emission and update decoder Jit flags accordingly, then extend invalid-offsetof suppression across cpu/recompiler.cpp to match the RSP pattern.
Verbose refactoring to only use decoder.cpp for extracting information
from opcodes (removing isTerminal and the return value of emit functions).
Added tracing to the cache index so that we basically version the JIT
blocks depending on whether it is enabled or not. This allows to
implement support for emux tracing without overhead.
This generates optimized codepaths for lqv and sqv. It also relies on
constant tracking to optimize situations where the base address is
know at JIT time (very common) and we can thus prove its alignment.
The JIT now tracks constant registers within each recompiled blocks.
This is currently unused in the generated code, will be useful to
improve code generation for vector load/stores opcodes.
This is non trivial because input arguments might mistakenly override
ABI registers. Prevent register argument clobber by resolving move
dependencies and breaking cycles with a temporary register.
Move UsesDmem and MayHalt traits into OpInfo so decoder metadata directly drives recompiler decisions, and simplify the JIT loop by unifying delay-slot state while documenting the current architecture and optimizations.
Drop the JIT write-sink indirection and skip code emission when the destination is R0, while keeping side-effecting C++ helpers and guarding their writeback to preserve R0 semantics.
Emit status.halted exit checks only for instructions that can mutate halt state (BREAK and MTC0 to SP_STATUS), reducing per-opcode overhead in the main JIT loop.
Do not classify VU opcodes as callf preflush candidates so deferred clocks are only synchronized for paths that actually require clock-visible C++ calls.
Track deferred clock progress for slow-path entries so memory fast paths avoid callf-triggered flushes while preserving correct timing when deferred fallbacks execute.
Emit direct fast paths for LB/LBU/LH/LHU/LWU/SB/SH/SW and keep unaligned half/word cases in deferred slow paths, reducing callf overhead while preserving interpreter behavior.
Keep deferred slow-path records minimal and re-enter opcode emission in slow mode, reducing per-opcode slow-path boilerplate while preserving the compact LW fast path.
Implement DMEM read/write paths with MSB-first word semantics and byte-accurate unaligned wrapping. Adjust RSP DMA DMEM transfers to use word paths consistent with the new DMEM representation while preserving IMEM behavior.
Replace the delay-slot call to instructionEpilogue<1> with explicit clock flush plus instructionBranchEpilogue, removing wrapper overhead while preserving delay-slot branch semantics.
Replace the JIT call to RSP::step with a direct thread clock increment while keeping deferred clock flushing behavior, reducing hot-path call overhead without changing interpreter behavior.
Defer fixed clock stepping across pure inlined opcodes and flush before callf paths, delay-slot handling, halts, and block exit to preserve observable timing while reducing hot-path step calls.
Emit the DelaySlot|EndBlock mask directly into branch state destinations for conditional branches, removing temporary state move instructions in the hot path.
Emit branch state updates directly in non-delay-slot branch paths and avoid copying nstate into state in the non-delay-slot epilogue, reducing branch-state traffic in the hot path.
Pass delay-slot phase into EXECUTE/SPECIAL/REGIMM emitters so branch-like ops can write the active destination directly and remove redundant delay-slot branch.begin state traffic.
Use compile-time next-PC values for non-delay-slot commits and avoid per-op branch.begin updates outside delay slots, reducing hot-path branch state traffic while preserving delay-slot behavior.
Use a compact xor-mask select for conditional branch target/fallthrough selection, reducing generated hot-path instructions while preserving existing branch semantics.
Replace runtime fallthrough reads from branch.nextpc with compile-time PC+8 immediates for REGIMM and EXECUTE conditional branches to remove extra hot-path memory dependencies.
Include block base address in the RSP JIT hash and use compile-time branch targets for conditional branches so generated code stays correct while removing extra runtime target math.
Pass the current block PC into RSP JIT emitters and use compile-time PC+8 immediates for JAL/JALR/BLTZAL/BGEZAL link register writes while keeping existing branch flow unchanged.
Skip branch state/pc commit work for non-branch non-terminal opcodes and simplify branch begin emission, and fix BLTZAL/BGEZAL when Rs aliases RA by deferring link write until after condition evaluation.
Emit BEQ/BNE/BLEZ/BGTZ and REGIMM conditional branches directly in JIT to remove per-opcode C++ calls while preserving delay-slot and link-register behavior.
Drop the fastInstructionEpilogue runtime toggle now that the specialized JIT epilogue path is stable. Keep the delay-slot fallback path while making the optimized path the only code path.
Choose the fast epilogue path at compile time for non-delay-slot instructions and keep the legacy path only for delay slots. This removes per-opcode branch-state dispatch in the hot path while preserving behavior.
Replace the slow-path JIT epilogue call with direct step/clocksTotal updates and a call to instructionBranchEpilogue, keeping branch exit semantics unchanged. This reduces call overhead while preserving behavior under the fast epilogue toggle.
Store RSP IPU PC as 32-bit so JIT word-sized accesses cannot clobber adjacent state. This keeps the fast epilogue path behaviorally stable while preserving 12-bit address masking semantics.
Add an A/B switch for a fast JIT epilogue path while preserving the legacy path as fallback, and widen branch pc storage so JIT word-sized accesses are safe. This gives a stable way to compare behavior and performance during further tuning.
Model RSP branch flow with pc/nextpc and latched state/nstate so interpreter and JIT follow the same delay-slot and end-block semantics. This stabilizes branch behavior while keeping stall and dual-issue logic unchanged.
Refactor reset handling to align with project architecture by removing the
'resetting' flag from the MOS6502 core. The reset state is now managed via
'resetPending' within the specific A2600 and Famicom CPU implementations.
- MOS6502: Remove resetting flag and internal reset logic from power().
- CPU: Introduce io.resetPending to handle reset triggers in the main loop.
- Debugger: Add interrupt/reset notification support for better tracing.
- Serialization: Update A26 (v140) and FC (v152) versions for state changes.
- Implement Dendy-specific timings: CPU divider 15, 312 total scanlines, and vblank starting at scanline 291.
- Refactor CPU/APU rate calculation to use a dynamic system divider instead of hardcoded PAL/NTSC checks.
- Add Dendy to the system region enumeration and UI emulator list.
- Handle Dendy-specific hardware differences: disable microphone input and adjust PPU aspect ratio/pixel output offset to match PAL-like characteristics.
- Clean up controller and system unloading logic to prevent memory leaks.
This implements a first subset of the emux extensions on the RSP. The
implementation is similar to the CPU one, and forwards to it things
that have to be identical.
Emux is a spec for emulator extensions to help homebrew development.
The spec can be found here at the time of writing:
https://hackmd.io/@rasky/r1k7na6Jn
Usage of emux is gated behind the "homebrew development mode" setting.
This commit introduces support for several extensions on the CPU, but
none on the RSP yet.
For homebrew profiling features, we need to track what hardware device
is accessing the shared RDRAM. We do have this already for debugging
purposes as a string. This commit changes that to an enum.
Normally, cores shouldn't be able to request the emulator to shut down
on the host computer, but this might be required for some homebrew
development features.
Previously the condition checked for MINGW, treating MSVC and all other
toolchains as a single "no detection needed" case. This inverts the
guard to MSVC, so that MSVC correctly skips detection (Windows SDK
provides xaudio2 directly) while MinGW and other non-MSVC toolchains
go through the CheckCXXSourceCompiles probe as intended.
Add cmake/finders/FindXAudio2.cmake to replace the ad-hoc XAudio2
link logic in os-windows.cmake. On MinGW, the module uses
check_cxx_source_compiles to probe for xaudio2_9 and xaudio2_8 in
the sysroot; on MSVC and other toolchains the Windows SDK umbrella
library is used directly. An imported target XAudio2::XAudio2 is
exported so call sites need no platform conditionals.
Replace the generator-expression-based -gcodeview selection in
compilerconfig.cmake with an explicit check_cxx_compiler_flag probe
at configure time (ARES_COMPILER_SUPPORTS_GCODEVIEW). This avoids
passing -gcodeview to toolchains that do not support it and makes
the fallback to DWARF visible in the configure log rather than
silently resolved at build time.
- ruby/cmake/os-windows.cmake: call find_package(XAudio2) and
consume XAudio2::XAudio2 via a generator expression; remove the
old MSVC/else block that unconditionally linked xaudio2/xaudio2_9
- cmake/windows/compilerconfig.cmake: add -gcodeview capability
probe; rewrite Clang and GCC debug-symbol blocks to branch on the
cached result instead of a generator expression
We were rendering background and sprites in burst mode, which shouldn't
happen.
I'm not the author, I'm just upstreaming changes done a member in our
team.
- Implementation of JY Company (Mapper 90, 209, 211) with support for
complex PRG/CHR banking, IRQ counter modes, and math registers.
- Implementation of SC-127 (Wario Land II Kirby hack) with A12-based
IRQ filtering.
- Enhanced CPU with `isWriting()` check and PPU with `isRenderingRead()`
status to support advanced mapper timing.
- Updated MIA database to recognize iNES mappers 35, 90, 209, and 211.
Currently Ares implements an infinitely fast EEPROM, but alas real
EEPROMs can take even 20 ms to save a single block of 8 bytes.
This commit implement approximate timings and the related flag to
notify the CPU that the EEPROM is busy writing data.
Introduce a `--batch` command-line option to run with a minimal presentation for frontend-driven launches (eg EmulationStation, arcade cabinets etc).
Behavior
- `--batch` implies `--no-file-prompt`
- Requires at least one valid game path (otherwise exits with a clear error)
- Uses a minimal presentation:
- hides menu bar
- removes status bar
- black background / centered viewport
- keeps file-open and drag/drop support
- Skips constructing settings/tools/game-browser windows in batch
Runtime safety
- Batch mode avoids UI-only flows where possible (logs messages instead)
- Driver and load/identify failures trigger a clean batch exit path
- Runtime defocus checks now use `settings.input.defocus` instead of `driverSettings.*.checked()`:
- avoids dereferencing non-constructed UI widgets in batch
- fixes batch crash from UI-state reads on non-UI code paths
`Program::quit()` could call `unlock()` on a `unique_lock` that did not own
the mutex, triggering `std::system_error` ("Operation not permitted")
and terminating the process on exit.
Guard the `unlock()` call with `owns_lock()`.
Call scheduler.setSynchronize(synchronize) during PS1 serialization
to match the behavior used by other cores.
Without synchronized serialization, coroutine/thread state may be
captured inconsistently, which can lead to crashes or undefined
behavior when loading savestates after relaunch.
Bump serializer version to v147 to invalidate incompatible v146
savestates created without scheduler synchronization.
The multi-byte read handler for the RCP/PI address range
(0xA4000000-0xBFFFFFFF) correctly fills the result buffer via
bus.read<Word> but then falls through to `return {}` instead
of returning the result. This causes GDB memory reads from ROM
cartridge addresses to return empty responses.
CMake install(DIRECTORY "path") without a trailing slash copies the
directory itself, creating an extra shaders_slang/ level under Shaders/.
Adding a trailing slash makes it copy the contents directly, consistent
with macOS (ditto) and Windows (copy_directory) which both copy contents.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
On a real console, when the AI DMA ends, even if the volume is not zero,
there is a decay happening on the analog path that doesn't cause any
audible pops. This can happen in games when they fail to meet the
audio deadline and schedule a new buffer before the previous one ends.
When the homebrew header was first introduced, in its first limited
spec, Ares defaulted to enable both rumble pak and controller pak:
https://github.com/ares-emulator/ares/commit/bc8c308ee96162f5a7068001a0ece83e5f821e16
Back at the time, there wasn't any way to specify that a controller pak
was needed by the ROM, and Ares didn't even provide a GUI to install it.
So basically this was the only way to allow a homebrew game to use
the controller pak at all.
Fast forward 4 years and now we have a GUI to select which pak to install
on each controller, and the homebrew header allows to pre-install whatever
you want into each port.
In case the user doesn't specify a suggested controller configuration
in the homebrew header, the default of using a controller pak has the
annoying side effect of creating a useless .sav file next to any ROM.
CPak is not very common in homebrew ROMs anyway, so enabling it by
default now seems to create more hassle than it solves.
The advanced homebrew header (https://n64brew.dev/wiki/ROM_Header)
specifies a bit to mark a ROM as "region free", meaning that it can be
booted in all regions. Ares now has a region preference option, so
that option can be respected for the region free ROMs.
- cpu: implemented memory timing/control registers
- cpu: update bus accesses to obey memory timing registers
- cdrom: incorrect 150lba offset in command 0x14
- cdrom: fix behavior when a command is issued before the previous has completed
- cdrom: implement behavior where a new command cannot be executed until pending IRQ are acknowledged
- cdrom: implement 'command/parameter busy' register
- dma: update bus accesses to obey memory timing registers
- dma: improve chopping/allowing the cpu to run between blocks of a long transfer
- mdec: implement basic decode timing
- mdec: implement correct input fifo behavior
- mdec: fix behavior when an incomplete block is transferred via the input fifo
- mdec: fix dma request registers, input/output full/empty registers, busy register
- gpu: use correct clock frequency for PAL and NTSC
- timer: improve behavior around timer overflow/target reached irq
When placing co_swap_function byte array into the text section, libco
uses the trick of appending a # to the section name. This name string is
passed directly to the generated assembly and the # is treated as
comment token by the GNU assembler. This is a hack to avoid a warning
about changed section attributes.
This hack doesn't work with other compilers like Clang or TinyCC, but
unlike GCC they don't require such hacks. I've added some compile time
checks around the hack to try to isolate it to GCC and allow other
compilers to see the unmodified section name.
Validated on the following OSes/architectures/compilers:
- Windows/amd64: gcc, clang, cl, clang-cl, tcc
- Windows/aarch64: clang, cl, clang-cl
- Linux/amd64: gcc, clang, tcc[1]
- Linux/aarch64: gcc, clang, tcc[1]
- macOS/aarch64: gcc, clang
[1] TCC only works with a fix to glibc headers that was only made very
recently. Without it, you have to #undef __attribute__ after including
glibc headers.
This is required on amd64 due to the aligned moves in co_swap. While
note technically needed on aarch64, I found information online that
suggested ldp/stp perform better on certain microarchitectures with
16-byte alignment.
VI_H_TOTAL is defined as the number of cycles per scanline *minus 1*.
We forgot to add that 1 back. Besides the minor inaccuracy in timing,
we could hit a race condition during initial VI config: if the Ares
VI thread ran when the display was turned on (VI_CTRL configured) but
VI_H_TOTAL wasn't already configured (and thus defaulted to 0), the
thread would spinloop forever because it would step by 0 cycles.
While fixing this, I also noticed that I wasn't properly taking into
account leap timings because of a typo; this means that PAL timings
were very slightly off.
Fixes#2293
When beginning to execute a joybus frame, PIF clears the RX flags before
the transaction begins, so that errors notified in previous transactions
don't accumulate.
This is only visible in the where an application performs multiple
transactions (SI DMA reads) on the same frame layout (sent via a single
SI DMA write), while controllers are being hotplugged. This is not very
common in Ares, which is probably why it was not noticed before.
- Replace all nall::vector declarations with std::vector in desktop-ui
- Update API calls: .append() -> .push_back(), .reset() -> .clear()
- Replace .takeFirst()/.takeLast() with .front()/.back() + .erase()/.pop_back()
- Convert .find() to std::ranges::find() and std::ranges::find_if()
- Replace .sort() with std::ranges::sort()
- Fix boolean conversions: if(!vector) -> if(vector.empty())
- Migrate all emulator-specific files and core desktop-ui components
- Use direct assignments between std::vector instead of manual loops
- Maintain compatibility with nall::split() by using auto type deduction
genius can't build with Qt as it uses ComboEdit, but it is currently
enabled in the ubuntu-ci-qt as it inherits the base ubuntu-ci (which is
GTK-based).
GCC evaluated the always failing assert before the constexprs leading
to it, resulting in a compilation failure. As a workaround, we can move
the 'imm64' case inside the else block and check for the type there,
which also catches unhandled types at compile time.
Uses the new 'callf' function instead of 'call' in generated code. In
the n64-systemtest ROM, this change shaves off 6% and 10% of the
respective VR4300 and RSP median block sizes:
VR4300 block size statistics
min max mean median
before 113 6369 893.93 573
after 104 5937 881.17 537
RSP block size statistics
min max mean median
before 97 19196 3941.95 5336
after 88 17044 3414.06 4606
Also, on a benchmark with an RSP-intensive homebrew libdragon ROM, this
change gave about 1% actual runtime speedup.
When ares switched to SLJIT, some tiny overhead was introduced in every call
from guest to host code on 64-bit Linux. This was due to the argument register
mapping differing between SLJIT's own convention and the System V AMD64 ABI.
This commit makes the recompiler put function arguments directly in the correct
registers.
This commit introduces a new 'callf' template function that accepts recompiler's
'mem' and 'imm' argument types. It abstracts away the register setup so that
different host platforms can implement their optimized function calls. This also
results in slightly shorter code in the recompiler (see the followup commit).
The SLJIT_CALL_REG_ARG type of call is actually meant for SLJIT's own, optimized
calling convention, but since it assumes function arguments are placed in
correct registers, it works here. The only other option I could think would've
been emitting x64 machine code directly.
A simple implementation that is only accurate for 4-byte or 8-byte
aligned writes. Smaller accesses will require a full implementation of
write masking to be accurate.
ubsan on Mac caught an issue in this method: all geometry coordinates
are floats out and into Cocoa, but intermediate calculations were
being performed with u32 that caused undefined behavior when negative
numbers were involved.
- Use std::erase and ranges::find where shorter.
- Replace ranges::distance with iterator subtraction.
- Enable <ranges> in hiro core/extension; use views::reverse for reverse-destruction loops.
- Minor cleanups (array_view ctor from vector, build fixes).
- array-view/span: include <vector> so std::vector constructors are visible on stricter compilers
- directory (Windows): make ufolders/ufiles return std::vector<string>; update locals accordingly to match headers
Build verified locally with ninja.
- Add Pak::append(std::vector<u8>&, string) overload to accept std::vector without wrappers
- Convert remaining callers to pass std::vector directly; remove redundant array_view wrappers
- Replace nall::vector truthiness/foreach assumptions with std::vector equivalents (!empty(), range-for)
- Use std::vector APIs consistently (push_back; insert with begin()/end() when merging)
- Align medium analyze signatures/callers to std::vector where required; no semantic changes intended
- Keep explicit array_view only for subspans (pointer+length) where necessary
Build verified with ninja.
- directory, zip, mmi, cue: switch public APIs to std::vector; fix sort/find/append
- vfs/cdrom: use std::vector buffers and wrap into array_view when needed
- hid: replace inheritance from nall::vector with std::vector-backed fields
- instruction-set: use std::vector for cpuid data blocks
- windows/registry: contents() returns std::vector<string>
- set: iterator internals use std::vector stack
- tcptext socket/server: move buffers and onData() to std::vector<u8>
- remove umbrella includes of <nall/vector.hpp>
Callers fixed accordingly (ares/mcd, mia, desktop-ui).
Qt 5 introduces QScreen, which can be used to implement most of the
functionality needed by Monitor, although some of it probably won't make
sense when using Wayland.
Qt 6 no longer allows us to poll for the status of the event loop.
However, Qt 6 does still have a processEvents function, and the version
with the timeout actually spins the event loop and returns as early as
there are no more events in it. That's basically what we want to do. We
could run this with a really huge timeout, but that would just make it
more likely that hiro freezes up, so instead let's mirror hiro/gtk3 and
use a 50ms timeout.
This does not seem to be used anywhere in bsnes, higan or ares. It's not
really possible to implement with Qt 6, which has stop exposing this
detail of the event loop. It turns out this is actually OK, since we
don't *really* need it anyway, and in the case of hiro/qt, the
replacement should be more robust anyways.
Qt 5.0 adds the QScreen API, which exposes enough information that
Desktop::{size,workspace} no longer needs to fall back to Win32/Xlib. I
manually tested that this seems to give the same exact answers as the
Xlib path (though it technically goes a different route for
Desktop::size.)
Qt 4.8 LTS was released on December 15th, 2011. It hit its official
end-of-life on December 31st, 2015. It has been dead for nearly 10
years. Qt 4 is now so old, that it has been removed from Debian long
enough that "qt4" doesn't show up in *any* of the indexed package suites
in Debian's online package search service.
The CMake build of ares never supported Qt 4 in the first place, so this
code should all be dead anyway.
Now that the usage issues with string_view have been resolved it can be
safely used to wrap a vector<u8>. I'll note that passing a vector<u8>
directly to the string constructor would work as well (thanks to a
stringify overload) but I'm preserving the wishes of the author of the
MegaLD code to keep the type conversions explicit.
I'll also note that we're still constructing a string from the
string_view when we call JSON::unserialize(). Ideally, it would take a
string_view instead of a const string& and we could avoid the copy.
Unfortunately, all of the markup decoders currently require the input to
be null-terminated, which is only guaranteed by the string class.
Previously, string_view had a constuctor that allocated a new string and
forwarded all arguments to the string constructor. Among other things,
this allowed construction of string_view objects using any of the
various stringify overloads. However, there were drawbacks:
1. The constructor string_view(const char*, u32) shadowed the
forwarding constructor, leading to very different behavior. In the
forwarding version, the first parameter would be treated as a
null-terminated string, and the second parameter would be formatted
as a string and concatenated with the first.
2. Having both owning and non-owning modes makes it difficult for
someone reading the code to reason about lifetimes, as they depend
on how the object was constructed. It also deviates from the
behavior of the identically-named standard C++ string_view.
This commit splits the PI DMA-Write transfers (that is, loads from ROM)
in multiple blocks, following what happens on real hardware. Moreover,
it tries to more accurately reflect timing that each block takes. This
is easier to be done at the block granularity, otherwise the timing
algorithm would need to figure it out again the whole block splitting
logic.
From the point of view of the running application, now a ROM con see
the two hardware registers PI_CART_ADDR and PI_RDRAM_ADDR increment
one block at a time during the transfer, which more accurately reflect
what happens on real hardware.
This commit is validated with n64_pi_dma_test test ROM
(https://github.com/rasky/n64_pi_dma_test) which we now pass in full,
including timing tests with the default 10% tolerance.
This allows callbacks for repeated events (rescheduled at each callback)
to not have additional latency caused by the latency with which we call
step().
The homebrew header supports configuring a different controller and pak
for each port, but mia couldn't represent that in the manifest. The
required change is trivial though.
For backward compatibility, if the homebrew header doesn't declare
anything (which is the same as asking for a standard controller in all
four ports with no paks), we install a cpak in port 1 and a rpak in
port 2, which is also what we have been doing forever with commercial
games.
Controller pak formatting had two bugs: checksum calculation was wrong
(didn't really iterate on all bugs), and the FAT backup copy was in the
wrong position.
Pixel perfect (1.1 PAR) can still be achieved "Scale:Integer" combined with "Aspect: No correction"; this works better than the 'Pixel Perfect' setting ever did.
Currently, Ares has an "Aspect Correction" checkbox that allows to
disable the PAR (pixel aspect ratio) configuration made by each core,
to basically display the framebuffer without any additional scaling,
with host PC aspect ratio.
In addition to this, it is common for people to request an
"anamorphic 16:9" option, to correctly display games the way they would
appear on a 16:9 TV when stretched. Sometimes, homebrew games are even
designed to be viewed like this.
This PR changes the aspect mode from a boolean to a 3-value option.
The standard option is now named "Standard (4:3 TV)", and a new
option called "Anamorphic (16:9 TV)" is added.
Currently, we render PAL games as 640x480 which is wrong because PAL has
more vertical resolution. This causes PAL graphics to be reduced in
quality compared to a real output.
This commit renders PAL at 640x576 which is the commonly used active
display area used by PAL games, and then configure the aspect ratio to
make sure the output is correct.
/Oi, /Ob2, and /Ot are implied by /O2, which CMake adds by default in
Release and RelWithDebInfo builds. In RelWithDebInfo builds CMake also
downgrades inlining by adding in /Ob1, but we already have a workaround
for this. MinSizeRel builds may see a change in behavior, where CMake
passes /O1 instead, but in any case that is the recommended flag for
minimizing binary size.
The removal of /GL is especially important for MSVC builds. CMake will
add it when IPO is enabled, and forcing it on for all non-debug builds
was not simply redundant; it was overriding the user preference
expressed with ENABLE_IPO. ClangCL requires other flags to enable the
equivalent LTO feature, and this is already addressed elsewhere.
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.
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.
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.
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.
* 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
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
- 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
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.
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.
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.
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.
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.
* 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
* 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
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.
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.
- 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
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.
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.
Loaded 100 of 2738 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.