Compare commits

...
780 Commits
Author SHA1 Message Date
remutro 0aafd85789 Fix build warning 2026-05-28 13:42:30 +01:00
Luke Usher 67b0bf7aac ruby: improve SDL audio sync on non-stereo devices
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
2026-05-28 08:47:04 +01:00
remutro 11d887c99c Fix aspect correction menu radio items in GTK 2026-05-28 08:10:27 +01:00
Luke Usher 7c03fb208f desktop-ui: add tape position slider 2026-05-25 16:23:20 +01:00
Luke Usher b33edf5f90 sg/fc/msx/spec: update serialization for tapes 2026-05-25 16:16:05 +01:00
Luke Usher 83369fd40f sg: add tape support to sc-3000 2026-05-25 16:11:50 +01:00
Luke Usher 6ee42f25b4 msx: hook up tape recording to tape manager 2026-05-25 15:39:46 +01:00
Luke Usher fe388a7fcc desktop-ui: fix tape recording button attribute lookup 2026-05-25 15:33:23 +01:00
Luke Usher c7d667fa07 ruby: fix keyboard mappings on macOS by adding missing left/right modifier keys 2026-05-25 11:36:27 +01:00
Luke Usher cc0e405780 msx: use the 'new' tape system rather than hard-coding the tape deck, add support for tsx/tzx and cas.
also prevent creating a .wav when not writing
2026-05-25 10:07:32 +01:00
Luke Usher c21adc7b57 spec: use the 'new' tape system rather than hard-coding the tape deck 2026-05-25 09:25:10 +01:00
Luke Usher 232f85e39c desktop-ui: move dynamic scale options to a vector rather than a grouo
Fixes being able to select multiple scaling-related options simultaneously
2026-05-24 23:40:30 +01:00
Luke Usher c951652efb desktop-ui: fix broken virtualpad overrides 2026-05-24 23:02:26 +01:00
Luke Usher f605d52032 desktop-ui: replace multiplier sizing with viewport sizing and re-add manual integer scaling ratios
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.
2026-05-24 20:29:39 +01:00
Luke Usher bdd585a563 hiro: cleanup some macOS compile warnings and deprecation notices 2026-05-24 17:57:20 +01:00
Luke Usher 54fc194182 desktop-ui: persist SDL joypad mappings by GUID slot
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.
2026-05-24 17:38:35 +01:00
user 4c39ca23eb gba: skip rendering sprites that are offscreen horizontally 2026-05-24 17:02:16 +01:00
user 8ea87c75e4 gba: implement OAM stage timings for OBJ engine 2026-05-24 17:02:16 +01:00
Morilli 7f0f91b3da sfc: fix ppu horizontal offset in high-resolution offset-per-tile mode 2026-05-23 16:00:34 +01:00
Luke Usher 164f5648bf ruby: stabilize joypad identity and duplicate device handling for the SDL driver 2026-05-21 14:45:20 +01:00
Luke Usher 19cce7dbba ld: fix LaserActive video seeks after CD-ROM refactor 2026-05-20 20:05:50 +01:00
Giovanni Bajo 765c0d4181 n64: fix partial load/stores in little-endian mode
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).
2026-05-18 19:44:25 +01:00
Luke Usher fbc8f22821 desktop-ui: default overscan to true
More natural window aspect by default, especially in PAL regions.
2026-05-17 19:41:04 +01:00
Luke Usher 14f4fc0173 desktop-ui: add direct input mapping mode with VirtualPad fallback
(AKA core-specific input mappings!)

Also adds support for direct input devices that bypass VirtualPad entirely, currently used for Mahjong
2026-05-17 19:40:33 +01:00
user 6920622b7e gba: add OAM to memory viewer 2026-05-17 19:17:02 +01:00
Giovanni Bajo c42bb2626d n64: implement VR4300 reverse-endian mode
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
2026-05-17 19:16:48 +01:00
Morilli d45be3297f sfc: Improve autojoypad polling accuracy 2026-05-11 10:57:30 +01:00
remutro 54adf82264 Update libchdr to version 0.3.0 2026-05-11 10:56:14 +01:00
remutro 7d1bbf7c04 Update libchdr to version 0.3.0 2026-05-11 10:56:14 +01:00
remutro d17ae2f36d Update libchdr to version 0.3.0 2026-05-11 10:56:14 +01:00
remutro b9f8347d57 Update libchdr to version 0.3.0 2026-05-11 10:56:14 +01:00
Giovanni Bajo 41af52ec27 n64: improve CPU JIT documentation 2026-05-11 10:53:35 +01:00
Giovanni Bajo 87daf87fbb n64: decrease a bit jit interleaving (unfreeze conker) 2026-05-11 10:53:35 +01:00
Giovanni Bajo 2a5b9fe74e n64: fix interrupt generation to never happen mid-instruction 2026-05-11 10:53:35 +01:00
Giovanni Bajo bb91ff1136 n64: fix a few cases where interrupt latency was still higher than expected 2026-05-11 10:53:35 +01:00
Giovanni Bajo 5d7496c6f1 n64: change CPU JIT flush message 2026-05-11 10:53:35 +01:00
Giovanni Bajo 18692c3ced n64: increase JIT interleaving and add more forced syncs on MMIOs 2026-05-11 10:53:35 +01:00
Giovanni Bajo bc3af76716 n64: reduce interrupt latency to zero in JIT 2026-05-11 10:53:35 +01:00
Giovanni Bajo 03dd55bbda n64: in CPU JIT, correctly declare 6 scratch registers (and don't use 7th) 2026-05-11 10:53:35 +01:00
Giovanni Bajo ffab36ed99 n64: in CPU JIT, verify internal assumptions on block links 2026-05-11 10:53:35 +01:00
Giovanni Bajo 8ad8803765 n64: in CPU JIT, implement LL/SC/LLD/SCD 2026-05-11 10:53:35 +01:00
Giovanni Bajo 3198e0e88e n64: in CPU JIT, rewrite branches to use branchless code 2026-05-11 10:53:35 +01:00
Giovanni Bajo 999d858fa7 n64: in CPU JIT, extend blocks also beyond jump and links 2026-05-11 10:53:35 +01:00
Giovanni Bajo a752515d2d n64: bump serializer 2026-05-11 10:53:35 +01:00
Giovanni Bajo 2460b01b27 n64: in CPU jit, synchronize CPU/RSP on status and semaphore I/O 2026-05-11 10:53:35 +01:00
Giovanni Bajo 2af310528b n64: in CPU JIT, fix LWR.
Also fix it in interpreter to align to newly tested corner case
(non sign-extended input).
2026-05-11 10:53:35 +01:00
Giovanni Bajo a1be16873f n64: in CPU JIT, compute homebrew dcache dirty mask after stores
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 8b4f1fa16e n64: CPU now has configurable interleaving with the rest of the hardware 2026-05-11 10:53:35 +01:00
Giovanni Bajo 882fc4df1f n64: split recompiler in three files 2026-05-11 10:53:35 +01:00
Giovanni Bajo 997077527b n64: in CPU JIT, cleanup to remove redundant structure fields 2026-05-11 10:53:35 +01:00
Giovanni Bajo dd834d2c5d n64: revisit integration between JIT and gdb to improve performance 2026-05-11 10:53:35 +01:00
Giovanni Bajo 50b9786587 n64: make sure events inserted in the queue affect JIT timings 2026-05-11 10:53:35 +01:00
Giovanni Bajo fbb6e72e02 n64: in CPU JIT, fix a bug in TLB handling (eg: Linux)
Now that the JIT can hardcode PC in generated code, each block is valid
for a single vaddr. It can't be reused.
2026-05-11 10:53:35 +01:00
Giovanni Bajo c152ef5639 n64: in CPU JIT, simplify decoder removing dead code 2026-05-11 10:53:35 +01:00
Giovanni Bajo 49af8ab6a2 n64: in CPU JIT, blocks now extend through branches
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 68134837d4 n64: avoid excessive JIT trashing by reducing the 4K section granularity 2026-05-11 10:53:35 +01:00
Giovanni Bajo bb75c2f058 n64: in CPU JIT, do not emit pipeline prologue for linear instructions 2026-05-11 10:53:35 +01:00
Giovanni Bajo 105e8da924 n64: in CPU JIT, make epilogue code conditional in fast paths 2026-05-11 10:53:35 +01:00
Giovanni Bajo b0de6c11d2 n64: in CPU JIT, return pipeline information from emit functions 2026-05-11 10:53:35 +01:00
Giovanni Bajo b89a0bcce1 n64: in CPU JIT, add SDL/SDR/SWL/SWL/SWC1/SDC1 2026-05-11 10:53:35 +01:00
Giovanni Bajo 04f8b9cb4d n64: implement LWL, LWR, LDL, LDR, LWC1, LDC1 in JIT 2026-05-11 10:53:35 +01:00
Giovanni Bajo c139a4d4ad n64: in CPU JIT, use JIT-time PC for branches as much as possible 2026-05-11 10:53:35 +01:00
Giovanni Bajo 28f05b0297 n64: in FPU JIT, optimize comparisons 2026-05-11 10:53:35 +01:00
Giovanni Bajo 39b5d798b9 n64: in FPU JIT, implement compare opcodes (first draft) 2026-05-11 10:53:35 +01:00
Giovanni Bajo 7e5841d84a n64: in FPU JIT, add MOV.S/MOV.D implementation 2026-05-11 10:53:35 +01:00
Giovanni Bajo 8c3961cd6e n64: in FPU JIT, add comments and slight tweaks to underflow fixup 2026-05-11 10:53:35 +01:00
Giovanni Bajo e6517f5f57 n64: in FPU JIT, reduce input checks required for conversion opcodes 2026-05-11 10:53:35 +01:00
Giovanni Bajo cd604bf619 n64: in FPU JIT, reduce fallbacks to C++ for conversions in most occurrences 2026-05-11 10:53:35 +01:00
Giovanni Bajo 85008a663e n64: in FPU JIT, simplify a bit conversion opcodes 2026-05-11 10:53:35 +01:00
Giovanni Bajo 8031dcd3f2 n64: fix a benign typo in FCVT_D_L
It went unnoticed because it's basically re-running the same conversion
of the CHECK_FPE line, and probably rounding modes don't matter enough.
2026-05-11 10:53:35 +01:00
Giovanni Bajo f0b8a36b6a n64: implement float/int conversions in FPU JIT 2026-05-11 10:53:35 +01:00
Giovanni Bajo 36aed53124 n64: in FPU JIT, implement ALU double opcodes 2026-05-11 10:53:35 +01:00
Giovanni Bajo 1d8c89a50f n64: refactoring and cleanup of FPU JIT opcode emission 2026-05-11 10:53:35 +01:00
Giovanni Bajo 60007e8853 n64: in FPU JIT, implement FADD.S and FSUB.S 2026-05-11 10:53:35 +01:00
Giovanni Bajo 3542371b76 n64: in FPU JIT, unity 1/2 arity codepaths 2026-05-11 10:53:35 +01:00
Giovanni Bajo a8882a1d89 n64: in FPU JIT, add support for MUL.S and DIV.S 2026-05-11 10:53:35 +01:00
Giovanni Bajo 86fa83fc2b n64: in FPU JIT, implement passthrough of flag bits from host processor 2026-05-11 10:53:35 +01:00
Giovanni Bajo 71ddda52b5 n64: simplify FPU JIT by moving some code into nall/recompiler 2026-05-11 10:53:35 +01:00
Giovanni Bajo be0504e1c2 n64: start implementation of FPU JIT for amd64 too 2026-05-11 10:53:35 +01:00
Giovanni Bajo a34a6ab1df n64: implement initial FPU JIT, for ARM64 2026-05-11 10:53:35 +01:00
Giovanni Bajo 515cb06729 n64: in CPU JIT, remove the deferred pc/nextpc/pipeline materialization
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 2d852d6a9b n64: refactor to remove obsolete decoder JIT flags 2026-05-11 10:53:35 +01:00
Giovanni Bajo 5b8abb5717 n64: in JIT, add optimizations for accesses via $sp/$gp 2026-05-11 10:53:35 +01:00
Giovanni Bajo 496409c199 n64: implement also memory store opcodes in JIT 2026-05-11 10:53:35 +01:00
Giovanni Bajo 9e6be60b9e n64: implement all aligned load opcodes in JIT 2026-05-11 10:53:35 +01:00
Giovanni Bajo fdbd036bd1 n64: in JIT, remove confusing callf macro 2026-05-11 10:53:35 +01:00
Giovanni Bajo f241c4095d n64: optimize dcache to use a single word with both tag and valid bit 2026-05-11 10:53:35 +01:00
Giovanni Bajo 094454e52f n64: add JIT for LW as a first experiment 2026-05-11 10:53:35 +01:00
Giovanni Bajo dabeb68387 n64 cpu: inline MFC1/MTC1/DMFC1/DMTC1 in the JIT when COP1 is enabled.
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo cc82697f00 n64: in CPU JIT, inline icache management 2026-05-11 10:53:35 +01:00
Giovanni Bajo e3f4d6dc0d nall: add mov128 and mem0 for absolute addressing 2026-05-11 10:53:35 +01:00
Giovanni Bajo b698206d07 n64: in CPU JIT, inline fastpath of icache hit check 2026-05-11 10:53:35 +01:00
Giovanni Bajo 7451ccbc98 n64: in CPU JIT, simplify branch link management 2026-05-11 10:53:35 +01:00
Giovanni Bajo 6448413adf n64: JIT multiply/divide SPECIAL opcodes via SLJIT
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo d91f838e3b n64: lazily emit callf setup in CPU JIT
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo fc820aba6b n64: centralize JIT callf setup
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo a61dba8ec8 n64: JIT 64-bit shifts and trap opcodes
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 025cde8961 n64: JIT more 64-bit integer ALU operations
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 2f8659a375 n64: optimize CPU JIT ALU slow paths
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo f1eff7d2f0 n64: gate JIT pipeline state machinery on demand
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 0d3caa546c n64: defer nextpc materialization in JIT 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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo e7444fd852 n64: lazily commit ipu.pc in JIT loop
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 55ac593102 n64: materialize CPU pipeline pc only when needed
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 4ed8a7792c n64: flush deferred CPU cycles only on branch/helper opcodes
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 161f01fa0d n64: restore unconditional CPU JIT endblock checks
Revert conditional EndBlock test and epilogue gating in the CPU JIT loop to preserve control-flow behavior and keep the system tests passing.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 606151f79d n64: add virtual PC materialization in CPU JIT loop 2026-05-11 10:53:35 +01:00
Giovanni Bajo b00b1778d1 n64: avoid unconditional JIT step flush in hot loop
Only flush deferred cycles at the per-opcode boundary when an EndBlock check is needed, reducing helper-call overhead on straight-line JIT code.
2026-05-11 10:53:35 +01:00
Giovanni Bajo dc4af1ddad n64: gate JIT EndBlock checks on branch and helper ops
Skip emitting EndBlock test/jump in straight-line instructions where state cannot request block termination, reducing hot-loop overhead while preserving control-flow correctness.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 6b88fdfbbf n64: remove CPU JIT metrics instrumentation
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo edf712f2f6 n64: extend JIT branch linking to dual targets
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 70f1cf07c5 n64: add safe intra-section JIT block linking
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 6d6c5d5fad n64: refactor CPU JIT to introduce 4K sections and state key 2026-05-11 10:53:35 +01:00
Giovanni Bajo 3a44a460bd n64: add JIT documentation 2026-05-11 10:53:35 +01:00
Giovanni Bajo 8655d4027f n64: convert remaining CPU branch opcodes to JIT
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 271e545a49 n64: convert four CPU branches to JIT and silence offsetof warnings
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.
2026-05-11 10:53:35 +01:00
Giovanni Bajo 6b97edc9db n64: convert four more CPU branches to JIT
Convert J, JAL, BNE and BLEZ to direct JIT emission and update decoder metadata so these opcodes no longer follow the callf flush path.
2026-05-11 10:53:35 +01:00
Giovanni Bajo e4f4a7d657 n64: convert BEQ to JIT 2026-05-11 10:53:35 +01:00
Giovanni Bajo 861020eeb7 n64: initial cleanup of CPU JIT, introduce opcode decoder 2026-05-11 10:53:35 +01:00
Dragorn421 0dc20693e2 Remove "eat stdin" behavior on exit 2026-05-06 12:39:56 +01:00
Dragorn421 08746292c7 Fixup nall/nall/gdb/Readme.md (fix #1360) 2026-05-04 13:08:55 +01:00
Dragorn421 e2636505e2 Fixup versionconfig.cmake: pass --no-show-signature to the git command for getting the commit date 2026-04-30 10:40:59 +01:00
Dragorn421 2219f48fca emux v1.1: remove dashes from instruction names (#2518)
New emux spec location, for reference: https://n64brew.dev/wiki/Emux
2026-04-29 10:31:26 +02:00
Luke Usher 91c64bf350 mia: refactor identify to support when multiple systems use the same file extension
Update desktop-ui so that it prompts the user for the desired system if multiple results were returned, ignoring hidden systems.
2026-04-28 16:23:02 +01:00
kev4cards 6f6786e04f n64: add comment to fastSUV use with respect to SPV 2026-04-27 18:47:08 +01:00
remutro 7974cabb43 Minor Qt6 on Linux cleanup 2026-04-27 18:45:33 +01:00
remutro a8ae8fe83f Add ISViewer RAM to save states 2026-04-23 21:06:11 +01:00
remutro e7cdf9c046 Update dependencies (post-v147-2) 2026-04-23 18:19:26 +01:00
Giovanni Bajo 93c397dca7 n64: bump serializer 2026-04-23 18:19:14 +01:00
Giovanni Bajo c9f2773685 n64: silence invalid offsetof warnings 2026-04-23 18:19:14 +01:00
Giovanni Bajo 652d653736 n64: RSP JIT cleanup and add emux tracing support
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 219dff38ad n64: refactor load/store opcodes to make better use of constant addresses 2026-04-23 18:19:14 +01:00
Giovanni Bajo c5ca614492 n64: add LRV/SRV/SWV to RSP JIT 2026-04-23 18:19:14 +01:00
Giovanni Bajo 0fca58b98e n64: add LTV/STV to RSP JIT 2026-04-23 18:19:14 +01:00
Giovanni Bajo 5d04cd3808 n64: add RSP JIT for LFV/SFV 2026-04-23 18:19:14 +01:00
Giovanni Bajo 59a0a898e9 n64: add LHV/SHV in RSP JIT, and refactor LUV/LPV/SUV/SPV to always use SIMD 2026-04-23 18:19:14 +01:00
Giovanni Bajo a6499c3b49 nall: fix build on msvc and GCC 13 2026-04-23 18:19:14 +01:00
Giovanni Bajo 310b665160 n64: add LDV/SDV RSP JIT opcodes 2026-04-23 18:19:14 +01:00
Giovanni Bajo b96b8ac7da n64: add LSB/LSV/LLV/SSB/SSV/SLV RSP JIT opcodes 2026-04-23 18:19:14 +01:00
Giovanni Bajo d20a0e1b8e n64: add LUV/LPV/SUV/SPV RSP JIT opcodes 2026-04-23 18:19:14 +01:00
Giovanni Bajo 716d417359 n64: use sreg(3) in RSP JIT to hold the DMEM pointer 2026-04-23 18:19:14 +01:00
Giovanni Bajo 1b6893ea49 nall: allow a recompiler to define a different number of saved registers 2026-04-23 18:19:14 +01:00
Giovanni Bajo fef2ab4904 n64: in RSP, add JIT for lqv/sqv
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo cbf9f79e5f n64: add constant tracking in RSP JIT
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 4c4c5460bc nall: add support for register arguments to callf
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 26d5ac3a80 n64: specialize R0 source propagation in RSP JIT
Fold R0-based scalar and branch fast paths into direct immediates/moves so the emitter skips unnecessary register reads and compares.
2026-04-23 18:19:14 +01:00
Giovanni Bajo f71568bad4 n64: annotate RSP op metadata for JIT state handling
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo a4ac042f27 n64: skip R0 writes in RSP JIT paths
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 25e248a6c3 n64: centralize RSP JIT misaligned access capability
Define a single architecture capability macro for unaligned scalar memory access and use constexpr slowpath selection helpers for half/word DMEM ops.
2026-04-23 18:19:14 +01:00
Giovanni Bajo f43063803b n64: gate RSP halted checks to relevant opcodes
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 9e20c21b35 n64: avoid VU preflush in RSP callf gate
Do not classify VU opcodes as callf preflush candidates so deferred clocks are only synchronized for paths that actually require clock-visible C++ calls.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 44ab78ade5 n64: defer RSP JIT clock flushes to slow paths
Track deferred clock progress for slow-path entries so memory fast paths avoid callf-triggered flushes while preserving correct timing when deferred fallbacks execute.
2026-04-23 18:19:14 +01:00
Giovanni Bajo c88d2eba79 n64: JIT scalar RSP DMEM ops with deferred fallbacks
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo b1b51d3070 n64: re-emit RSP JIT slow paths via emitEXECUTE
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo dc8ac7d3dc n64: switch RSP DMEM accesses to big-endian semantics
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 3feb849778 n64: call branch epilogue directly in RSP delay slots
Replace the delay-slot call to instructionEpilogue<1> with explicit clock flush plus instructionBranchEpilogue, removing wrapper overhead while preserving delay-slot branch semantics.
2026-04-23 18:19:14 +01:00
Giovanni Bajo bc1009a5f1 n64: inline RSP JIT step clock update
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 1f06bbc156 n64: batch fixed RSP JIT clocks between call sites
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 09bb1cbf3e n64: fold RSP conditional branch state masking writes
Emit the DelaySlot|EndBlock mask directly into branch state destinations for conditional branches, removing temporary state move instructions in the hot path.
2026-04-23 18:19:14 +01:00
Giovanni Bajo b66752b4fc n64: write RSP branch state directly outside delay slots
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 97b9490845 n64: route RSP JIT branch targets by delay-slot phase
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 6e7cf80f6e n64: virtualize RSP JIT block PC progression
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo d250931aae n64: simplify RSP JIT conditional target selection
Use a compact xor-mask select for conditional branch target/fallthrough selection, reducing generated hot-path instructions while preserving existing branch semantics.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 7163fb4dbb n64: use virtual fallthrough PC in RSP conditional branches
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 838f4c6ad2 n64: stabilize RSP virtual-PC branch targets in JIT
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo c5e5c38a8a n64: use compile-time PC for RSP link writes
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 9f98c24394 n64: trim RSP JIT non-branch epilogue overhead
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 86765b1706 n64: inline RSP JIT conditional branch opcodes
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 2585b4667f n64: inline simple RSP JIT jump opcodes
Emit J/JAL/JR/JALR branch updates directly in JIT so these terminal opcodes avoid C++ calls while preserving current delay-slot behavior.
2026-04-23 18:19:14 +01:00
Giovanni Bajo bc4332bbb9 n64: remove temporary RSP epilogue A/B switch
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo a3d75ad5da n64: specialize RSP JIT epilogue by delay-slot position
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 101ba34f28 n64: inline RSP epilogue slow-path clock accounting
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo ece2001360 n64: widen RSP program counter storage
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 3e913fda53 n64: add toggled fast RSP instruction epilogue path
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo ec29392c11 n64: align RSP branch state with CPU pipeline model
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.
2026-04-23 18:19:14 +01:00
Giovanni Bajo 536fe6964f n64: factor RSP branch epilogue handling
Extract branch-state commit logic into a dedicated helper so we can iterate on JIT epilogue changes from a stable, behavior-preserving baseline.
2026-04-23 18:19:14 +01:00
remutro 18be35d9e0 Fix incorrect setting 2026-04-23 12:49:58 +01:00
remutro c6596bc468 Fix PlayStation extensions 2026-04-23 12:49:58 +01:00
remutro 00bdc72562 Fix MMI extension loading and detection 2026-04-23 12:49:58 +01:00
NovaSquirrel 0394fd90ad snes: update SerializerVersion to v145 2026-04-18 13:47:54 +01:00
NovaSquirrel f27d62f841 snes: fix SGB register mirroring to match hardware
According to fullsnes, SGB only decodes A0-A3,A11-A15,A22
2026-04-18 13:47:54 +01:00
NovaSquirrel 874d32eb42 snes: fix SGB logic for moving to next player
This is supposed to fix #1205
2026-04-18 13:47:54 +01:00
NovaSquirrel 8e10f41188 snes: Fix Super Game Boy $6002 and $700x registers
The Super Game Boy only stores one packet, and packet acknowledgement is done by reading $7000, not $6002
2026-04-18 13:47:54 +01:00
ZengGengSen ad98f53f3b refactor: move reset state from MOS6502 to system-level CPU
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.
2026-04-09 13:01:38 +01:00
ZengGengSen 6e0fa73249 fc: add support for Dendy region
- 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.
2026-04-08 09:12:51 +01:00
User 722f104fa0 gba: allow re-triggering keypad IRQ when input changes 2026-04-08 09:09:05 +01:00
Giovanni Bajo d55f80d633 n64: in emux, implement xioctl fast/slow
These can be used by testroms to automatically turn on fast forward mode
2026-04-07 08:53:16 +01:00
User 649a29debe gba: fix wave RAM bank selection 2026-04-04 08:56:02 +01:00
Giovanni Bajo dedc446418 n64: in emux, add detect mask for xioctl 2026-04-02 09:35:33 +01:00
Giovanni Bajo 16c5da5dc5 n64: implement emux on RSP
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.
2026-03-31 09:12:22 +01:00
Giovanni Bajo a0f762985e n64: add initial emux support
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.
2026-03-31 09:12:22 +01:00
Giovanni Bajo f76dd51134 n64: introduce RBusDevice for tracking devices accessing the RAM bus
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.
2026-03-31 09:12:22 +01:00
Giovanni Bajo 103dd93ae4 ares: add an event to allow a core to request emulator shutdown
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.
2026-03-31 09:12:22 +01:00
remutro 5f216a7bf5 Add Sega PAC firmware hashes for auto detection 2026-03-30 10:09:08 +01:00
User dfa6ec0c79 gba: improve affine parameter timings 2026-03-26 10:50:22 +00:00
User e011cbecbb gba: window accuracy improvements 2026-03-20 11:20:42 +00:00
Scott Mansell c2b349aeb8 cmake: Add missing include sources 2026-03-19 08:27:52 +00:00
remutro 6f0f7be867 Increase PCE Serialization Version 2026-03-18 14:57:43 +00:00
awsms bc86249658 desktop-ui: fix kiosk crash, ignore hotkeys while Tools window is focused 2026-03-18 12:19:06 +00:00
ZengGengSen 0ac4d8220c cmake: fix XAudio2 detection logic for MSVC vs non-MSVC toolchains
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.
2026-03-17 16:11:06 +00:00
ZengGengSen 1ce484be52 cmake: add FindXAudio2 module and fix debug symbol detection on MinGW
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
2026-03-17 16:11:06 +00:00
awsms 899ac2a2ed desktop-ui: prevent hotkey from firing when setting one 2026-03-17 16:09:33 +00:00
Florian-Simon-RedArtGames ca6974b66f Fix glitch in City Hunter ROM in the intro in the performance-mode VDP
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.
2026-03-17 16:08:37 +00:00
remutro 3d966bda8f Updated n64 serilization 2026-03-16 17:25:29 +00:00
remutro b11ee3fbdb Update serialized fields in N64 save states 2026-03-16 17:25:29 +00:00
User 3f8b0cae72 gba: slightly improve PPU timings 2026-03-16 17:25:20 +00:00
User 8261563a10 gba: fix mid-scanline toggling of background mosaic 2026-03-16 17:25:20 +00:00
remutro b15ce04e5d XAudio2 latency adjustment 2026-03-10 10:52:42 +00:00
ZengGengSen 7a515cd489 feat(fc): add support for JY Company and SC-127 boards
- 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.
2026-03-10 10:51:44 +00:00
Stefan Schlosser 5b7dafe70a CI: Update FreeBSD runner to 15.0
Update cross-platform-actions to v0.32.0 by using the explicit commit
https://github.com/cross-platform-actions/action/commit/492b0c80085400348c599edace11141a4ee73524

The change from 14.3 to a string literal '15.0' is mandatory, otherwise
the FreeBSD VM image cannot be fetched.
2026-03-08 16:35:08 +00:00
Luke Usher eaa47fbf9c a26: improve RIOT emulation, fixes Berzerk (likely others) 2026-03-06 21:14:18 +00:00
remutro bbc0c1db3b [PS1] Update state serialization 2026-03-06 18:57:35 +00:00
Giovanni Bajo b35a639e33 n64: adjust eeprom timings
Further hardware tests confirmed the EEPROMs are faster than initially
thought.
2026-03-06 15:23:54 +00:00
Giovanni Bajo 48b8c8a3ff n64: implement eeprom write timing and status flags
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.
2026-03-06 10:07:41 +00:00
awsms 5a80359443 ruby(audio): enable SDL_HINT_NO_SIGNAL_HANDLERS to avoid ctrl+C hijacks 2026-03-06 10:07:23 +00:00
awsms 67163a9fbe ruby: enable SDL_HINT_NO_SIGNAL_HANDLERS to avoid ctrl+C hijacks 2026-03-05 13:56:48 +00:00
remutro 0d1c90c616 Remove OpenGL macOS Video Driver 2026-03-04 13:06:56 +00:00
awsms 3678a4cc07 Introducing --kiosk mode (#2433)
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
2026-03-04 13:06:36 +00:00
Luke Usher c0a0f34439 ps1: fix some gpu clocking issues 2026-03-01 04:11:18 +00:00
Luke Usher 640ea5e3fa ps1: fix spu canReadDMA/canWriteDMA flags 2026-02-28 23:32:36 +00:00
Luke Usher cb40c6487b ps1: fix block dma using incorrect timing 2026-02-28 23:32:16 +00:00
Luke Usher 1570af44e2 ps1: fix incorrect bit position for dma channel chopping enable 2026-02-28 23:31:52 +00:00
Luke Usher d00c9feeac ps1: fix an issue where configured io access timing for exp1, exp3, bios, cpu, cdrom and exp2 would not apply 2026-02-28 23:30:24 +00:00
Luke Usher b308958bf0 cdrom: refactor CD-ROM session generation and image file handling
- Stop mixing time/address bases; we inconsistently treat LBA 0 as both 00:00:00 and 00:02:00.
 - Clearly separate logical and physical domains:
    - MSF: The MSF implementation assumes absolute MSF (lba 0 = 00:02:00)
    - LBA: logical addressing  (LBA 0 = Track 1 Index 01 / 00:02:00)
    - ABA: absolute addressing (ABA 0 = Track 1 Index 00 / 00:00:00)
 - Fix subchannel generation and support negative MSF (90–99)
 - Fix discs with non-default track 01 index 01 lba
2026-02-28 21:27:54 +00:00
Luke Usher 9125d0c79f ps1: rework cd-rom emulation 2026-02-28 21:27:53 +00:00
User ee80782345 gba: refactor bus reads 2026-02-28 09:45:06 +00:00
meauxdal b5fd6611f2 Update serialization.cpp 2026-02-27 19:55:12 +00:00
Luke Usher 12558c7ef3 gpu: fix hblank timing 2026-02-24 20:54:53 +00:00
awsms 99733cda7c fix abort on exit caused by invalid mutex unlock
`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()`.
2026-02-24 12:03:13 +00:00
awsms 1482689f09 ps1: enable scheduler synchronization
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.
2026-02-24 12:02:43 +00:00
Alex Bates a1d3fc19a2 n64: fix return GDB read result for RCP/PI bus path
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.
2026-02-23 19:15:23 +00:00
User 103770a995 gba: prevent instruction tracing from modifying open bus 2026-02-21 08:25:49 +00:00
Le-Syl21andClaude Opus 4.6 38a2e62603 Fix Linux shader install: copy contents instead of directory
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]>
2026-02-16 08:22:39 +00:00
meauxdal ae41a43567 n64: fix audio pops when AI DMA ends
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.
2026-02-15 22:53:40 +01:00
TascoDLX 08a7253e99 md: fix screen in interlace mode 1 2026-02-13 13:30:28 +00:00
remutro ba6069686f add missing file 2026-02-08 17:32:01 +00:00
remutro 6bb521a207 Import & export settings in the UI 2026-02-08 17:32:01 +00:00
remutro fac53a08ca Windows OpenGL 4.6 Core Profile Driver 2026-02-08 17:31:32 +00:00
izzy d67a92b2b4 make lambda more concise and strict 2026-02-08 17:31:12 +00:00
remutro ffee6d658d Fix fast forward getting stuck 2026-02-03 17:23:58 +00:00
remutro 58f3d7badf Exclude additional systems from using Run-Ahead 2026-02-03 17:23:36 +00:00
remutro 388e98fba9 Fix bug with disabling of secondary media 2026-01-30 06:40:08 +00:00
remutro f883420714 sort emulator cores by manufacturer 2026-01-30 06:40:08 +00:00
remutro d99f7598e1 macOS looks better using same value as Windows 2026-01-30 06:40:08 +00:00
remutro 64bfe58e03 Cleanup UI text and controls 2026-01-30 06:40:08 +00:00
meauxdal d05f7b64b4 Update vulkan.cpp 2026-01-28 07:55:22 +00:00
User bc036dcaf6 gba: improve handling of OBJ mosaic counters 2026-01-28 07:53:43 +00:00
User 64cebdad77 gba: fix interaction between OBJ mosaic and priority 2026-01-28 07:53:43 +00:00
remutro e594251208 add version string to end of help message 2026-01-27 10:12:38 +00:00
remutro cea26bd150 add option to print version string 2026-01-27 10:12:38 +00:00
remutro 27905a8fc7 Add ability to change disc for ldrom2 titles 2026-01-27 10:12:25 +00:00
remutro 2f2704b2b6 adjust string placement 2026-01-27 10:10:10 +00:00
remutro 5afa255ab8 logo alignment in about 2026-01-27 10:10:10 +00:00
remutro daa781706a Use lambda for sort comparer 2026-01-20 11:54:06 +00:00
remutro 88bd798427 Sort once when vector is created 2026-01-20 11:54:06 +00:00
remutro d77c8b1c56 Sort the emulators setting list also 2026-01-20 11:54:06 +00:00
remutro e07f18c172 Sort the emulator list in firmware settings 2026-01-20 11:54:06 +00:00
remutro 6bc13e8d66 Fix crash opening about window 2026-01-20 10:37:42 +00:00
remutro 25482bc539 Single xaudio2 source file, fix vector calls in asio.cpp 2026-01-19 14:34:34 +00:00
remutro 847e2a24cf Fix silly mistake 2026-01-19 14:34:34 +00:00
remutro 514933d459 Fix MSVC Linking 2026-01-19 14:34:34 +00:00
remutro 04e4f0ffa0 Fix MSVC builds 2026-01-19 14:34:34 +00:00
remutro 109c669056 Update XAudio2 from 2.1 to 2.9 2026-01-19 14:34:34 +00:00
Giovanni Bajo fb68c74143 n64: with homebrew header, don't default to install a controller pak
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.
2026-01-19 14:34:02 +00:00
remutro acdf31b40a Stay in pseudo-fullscreen when game is reset 2026-01-18 00:04:56 +00:00
remutro 48c611c90b Fix optnone attribute warning 2026-01-15 12:55:37 +00:00
remutro f338f50b4d some refactoring 2026-01-14 11:36:53 +00:00
remutro f0b119d90a Fix mapped drives not working after symlink fix (Windows) 2026-01-14 11:36:53 +00:00
remutro e8c268026c Update current save slot on successful save state load 2026-01-14 11:33:30 +00:00
remutro 9387eab814 Add command line option to specify a save state slot to load 2026-01-14 11:33:30 +00:00
remutro d769abafd9 Update hotkey text 2026-01-14 11:33:06 +00:00
remutro 742ab90d21 rogue spaces removed 2026-01-14 11:33:06 +00:00
remutro 2a346af4e2 Add hotkey to disable/enable selected shader 2026-01-14 11:33:06 +00:00
Giovanni Bajo df5ebc9245 n64: implement support for region-free ROMs (homebrew extension)
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.
2026-01-11 17:04:57 +00:00
Luke Usher 71f17d9a2a ps1: fix crash when saving/loading state 2026-01-09 21:00:32 +00:00
Luke Usher 4e7ab5d3e3 ps1: refactor core to use libco threading
- 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
2026-01-09 16:11:58 +00:00
remutro e5ffe61a07 Fix Dip Switches menu on Linux 2026-01-09 12:53:53 +00:00
remutro e601bccdfb Add pseduefullscreen command line argument 2026-01-09 10:27:41 +00:00
remutro 155c9b4154 Fix formatting 2026-01-09 10:27:31 +00:00
remutro 7b0e29baa9 Expose option to not prompt for secondary media in GUI 2026-01-09 10:27:31 +00:00
jsgroth 0152831319 m32x: adjust H32 pixel offset between Gen/MD VDP and 32X VDP
the adjusted offset is equal to 2.6 H32 pixels / 3.25 H40 pixels
2026-01-08 23:32:28 +00:00
remutro 17ce1bbe0f Fix loading shaders from the command line 2026-01-08 14:15:56 +00:00
remutro db953dbc62 minor format fixes 2026-01-08 09:27:05 +00:00
remutro 65ed77ecd7 Fix symlinks to files for rom loading 2026-01-08 09:27:05 +00:00
Luke Usher bdf4dc9ce1 desktop-ui: add '--settings-file' command line parameter 2026-01-07 10:32:43 +00:00
Luke Usher c01f3b885e desktop-ui: do not enable 'Arcade' if no arcade cores are compiled in. 2026-01-07 10:20:51 +00:00
Luke Usher 538078f6d0 ruby: prefer 'metal' video driver as both optimal and safest on macOS. 2026-01-07 10:11:43 +00:00
Luke Usher 2a4be17f56 ruby: remove erroneous include 2026-01-06 23:15:36 +00:00
ZengGengSen 9d647291fa add unload emulator to save the wav file 2026-01-06 16:32:21 +00:00
ZengGengSen 595de2e2aa fix new tape file resize bug 2026-01-06 16:32:21 +00:00
ZengGengSen 778e1f0b76 feat: add famicom data recorder support
1. add famicom data recorder support
2. refactor the tape control
3. fix the wav bug
2026-01-06 16:32:21 +00:00
User b5910c75f5 gba: prefetcher should fail reading across 128KiB boundaries 2026-01-06 16:21:35 +00:00
Luke Usher 23cd8772f5 ruby: allow drivers to set controller names and use deterministic device id in SDL driver 2026-01-06 12:09:44 +00:00
remutro 202db872de Add Cubivore English translation to N64 DB 2026-01-05 09:55:12 +00:00
remutro 934e9d36c3 Update dependencies (post-v147) 2026-01-02 16:21:26 +00:00
remutro 30066aa336 [SFC] Add support for GBC titles to the Super Game Boy 2025-12-31 12:33:22 +00:00
invertego cc4db18707 libco: limit scope of section hack to gcc
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.
2025-12-29 12:01:33 +00:00
invertego 30a3b125c8 libco: align co_active_buffer on amd64, aarch64
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.
2025-12-29 12:01:33 +00:00
User 084d8fb72b gba: only trigger keypad IRQ when input changes 2025-12-29 12:01:15 +00:00
User 463d44920b gba: fix handling of repeat bit during immediate DMA transfers 2025-12-27 22:38:59 +00:00
Stefan Schlosser adfc78f952 pce: fix missing qon linking 2025-12-23 14:44:52 +00:00
remutro f533120df6 Add noise channel to save state serialization 2025-12-18 12:44:55 +00:00
remutro ec37caccfb [N64] Fix pak menu radio selection 2025-12-09 11:50:14 +00:00
remutro d0b9669c50 Update CC92 based on agreed ROM and No-Intro entry 2025-12-07 16:33:51 +00:00
Luke Usher dfb355495a pce: fix missing cd-da playback 2025-12-01 16:03:05 +00:00
invertego 0f618995f4 mia: remove line of dead code 2025-12-01 15:47:30 +00:00
User 35ead94515 gba: implement write protection for HALTCNT 2025-11-28 16:05:42 +00:00
remutro 6c8ccc1c7e Add support for Viewpoint 2064 master to the N62 DB 2025-11-27 13:51:47 +00:00
Giovanni Bajo 361fb49fd0 n64: fix VI bug causing spinloop
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
2025-11-27 12:05:29 +00:00
Max Bebök 90139d028d increase n64 serialize version 2025-11-23 19:19:57 +00:00
Max Bebök d03915bde9 n64: handle correct R/W to RDP spans in test mode 2025-11-23 19:19:57 +00:00
remutro 8a7549fb21 Remove the entry for a test build of PF94 (already done for CC92) 2025-11-12 13:03:27 +00:00
remutro 6003e6933b [SNES] add db entries for newly dumped competition carts 2025-11-12 13:03:27 +00:00
Roger Sanders 35671b2f8d ld: Fix some media info registers. Fixes JB Harold side changing. 2025-11-04 11:33:39 +00:00
ZengGengSen 43686810d2 fix fc_keyboard support 2025-10-31 13:12:19 +00:00
Adrian Siekierka 9bd2afee61 ws: implement Karnak mapper ADPCM decoder 2025-10-29 14:55:07 +00:00
jcm 7bcb9ae39f build: Run gersemi formatting pass 2025-10-29 14:37:17 +00:00
jcm f39eac9b87 build: Add missing sources to CMake file enumeration 2025-10-29 14:37:17 +00:00
jcm f370521a55 build: Disable Metal GPU capture by default due to Xcode memory issues 2025-10-28 11:34:33 +00:00
jcm c763218430 build: Add ARES_DEBUG_DEPENDENCIES build option 2025-10-28 11:34:33 +00:00
jcm 2df5b97e5e build: Account for multiple possible prefixes in slang-shaders finder 2025-10-28 11:34:33 +00:00
jcm 0a7e1c5e4c Update dependencies to 2025-10-27 release 2025-10-28 11:34:33 +00:00
Adrian Siekierka 2d80fca221 ws: add I/O port access tracer support 2025-10-28 11:33:58 +00:00
User 3b8baddfba fc: fix evaluation of sprites not aligned to 4-byte boundaries in OAM 2025-10-28 11:33:49 +00:00
Luke Usher 5319fe68f0 screen: prevent blowing out brightness when increasing saturation. 2025-10-16 16:17:59 +01:00
User 6b11b281c4 fc: improve handling of OAM accesses during rendering 2025-10-16 07:10:01 +01:00
Rupert Carmichael c79a73e88c myvision: Adjust audio frequency to match real hardware
The divider is still unconfirmed, but 21 produces the correct pitch.

References:
https://gitlab.com/jgemu/jollycv/-/blob/master/src/jcv_myvision.c
https://www.youtube.com/watch?v=UqKuNb1Z9Uc
https://www.youtube.com/watch?v=RsNxhfD7iJk
2025-10-16 07:06:52 +01:00
remutro 53a63d6ae2 Resize board vector so that there are 2 entries minimum 2025-10-15 10:10:44 +01:00
Luke Usher c95ddfe754 tms9918: simplify/clarify timing.
The real chip expects colorburst*3 as input, and then divides that by 2 internally to get the pixel clock.
2025-10-08 10:03:48 +01:00
Luke Usher bfed5a56f0 myvision: adjust audio frequency to match other hardware with the same PSG.
Real hardware value unknown.
Still just a guess, but a better? guess than we had.
2025-10-07 21:42:02 +01:00
Luke Usher 41275f4a8a ym2149: implement readIO/writeIO
currently unused, but noticed support was missing compared to ay38910
2025-10-07 21:34:54 +01:00
Luke Usher 9fcb4f93e4 myvision: fix vdp clock to 2x colorburst. 2025-10-07 21:20:49 +01:00
png183 11a7827eef fc: bump serialization 2025-10-06 10:39:23 +01:00
User b7de9976a6 fc: values in CGRAM are six bits in size 2025-10-05 21:54:37 +01:00
DirtBag Xon 9671ec7c3d Fix ambiguous overload on mouseCursor types. Always compare with matching string types.
Fixes:
widget.cpp:142:20: error: ambiguous overload for ‘operator==’ (operand types are ‘const hiro::MouseCursor’ and ‘const nall::string’)

 142 | if(mouseCursor == MouseCursor::Hand) name = "hand1";
  | ~~~~~~~~~~~ ^~ ~~~~~~~~~~~~~~~~~
  | |           |
  | const hiro::MouseCursor const nall::string
2025-10-04 09:41:42 +01:00
Luke Usher cb4aec479f ps1: properly fix color modulation this time 2025-10-03 18:49:01 +01:00
Luke Usher 44f34f9bb2 ps1: improve color modulation
Fixes excessive colour banding, without breaking Silent Hill's loading screen.
2025-10-02 20:49:24 +01:00
Giovanni Bajo 90b6c0902d stdc++: remove nall::shared_pointer, now unused 2025-10-02 14:19:44 +01:00
Giovanni Bajo 445cfacb10 stdc++: migrate nall to std::shared_ptr 2025-10-02 14:19:44 +01:00
Giovanni Bajo 7989498177 stdc++: convert hiro to std::shared_ptr 2025-10-02 14:19:44 +01:00
Giovanni Bajo b38cacbab8 stdc++: convert ares/node to std::shared_ptr 2025-10-02 14:19:44 +01:00
Giovanni Bajo 4b121c28d0 stdc++: continue migrating most uses of nall::shared_pointer 2025-10-02 14:19:44 +01:00
Giovanni Bajo 4e1b4b79ef stdc++: start migrating nall::shared_pointer to std::shared_ptr 2025-10-02 14:19:44 +01:00
Roger Sanders 18500e679b ld: Fixed a potential threading issue with frame prefetch 2025-10-01 10:07:17 +01:00
Roger Sanders 174eb5bcf2 ld: Update minimum macOS target from 10.15 to 11.0 2025-09-30 14:57:05 +01:00
Roger Sanders 8d32ab3f4f ld: Fixed some missing includes which triggered build errors on some platforms 2025-09-30 14:57:05 +01:00
Roger Sanders 5cc3a8118f ld: Added frame prefetch and video resampling coefficient precalculation 2025-09-30 14:57:05 +01:00
User 753ba2af6a fc: improve frame counter IRQ timing 2025-09-30 08:57:24 +01:00
User 757f326c33 fc: reading APU status register should not affect open bus 2025-09-30 08:57:24 +01:00
Giovanni Bajo fc36600a6a stdc++: convert nall::unique_pointer to std::unique_ptr 2025-09-29 14:24:14 +01:00
Giovanni Bajo 038bcb91c2 stdc++: migrate nall::function to std::function 2025-09-29 14:24:14 +01:00
Giovanni Bajo 0b1714c8f6 stdc++: remove merge-sort.hpp, use std::stable_sort instead 2025-09-29 14:24:14 +01:00
User 76141ba703 gba: fix addressing of 2D mapped sprites 2025-09-27 16:14:19 +01:00
Giovanni Bajo 064b2120e4 stdc++: simplify span constructors 2025-09-27 16:14:06 +01:00
Giovanni Bajo 732d03f3af stdc++: apply review suggestions 2025-09-27 16:14:06 +01:00
Giovanni Bajo 81d0f131c4 stdc++: drop unused functions from span-helpers.hpp 2025-09-27 16:14:06 +01:00
Giovanni Bajo 5d0ff02cb3 stdc++: remove nall::array_span/array_view 2025-09-27 16:14:06 +01:00
Giovanni Bajo ba41375179 stdc++: convert uses in nall to std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo fe7f05fc1e stdc++: nall: convert some uses to std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo cbe2b7be32 stdc++: migrate missing uses in ares to std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo 0d1152de1c stdc++: migrate missing uses in ares to std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo eaf5e06683 stdc++: migrate most uses in mia to std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo 0921eb8038 stdc++: migrate serializers to std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo 64c8354511 stdc++: migrate vfs functions to use std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo cd21ca7bf4 stdc++: nall: migrate some uses of array_view/span to std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo ded925451b stdc++: introduce span-helpers.hpp to aid migration to std::span 2025-09-27 16:14:06 +01:00
Giovanni Bajo b0d5be69d0 stdc++: remove unusued / seldom used methods of array_view/array_span 2025-09-27 16:14:06 +01:00
Roger Sanders 2f7fa79b07 ld: Fix a potential out of bounds memory access in some video modes 2025-09-23 10:18:30 +01:00
Roger Sanders 4fd5318e52 ld: Fix image hold forcing a new frame to be latched when one was already in the buffer 2025-09-23 10:18:30 +01:00
Giovanni Bajo 810c508489 n64: fix PIF HLE on RX flag clearing
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.
2025-09-23 06:38:17 +01:00
jsgroth 383a0870f1 m68000: fix write ordering in MOVEM.L with indirect pre-decrement addressing
pre-decrement mode writes each longword in reverse-word order in addition to writing the registers in reverse order
2025-09-23 06:31:56 +01:00
Luke Usher 9e4a00b968 pc-engine-ld: detect and insert a bios hucard when a cd-rom is loaded that depends on it.
Currently non-working because mia rejects non-ld content for LaserActive right now, but it's here for when we fix that!
2025-09-22 13:37:55 +01:00
Luke Usher a57cce6b94 pc-engine-ld: use internal bios rather than incorrectly mountitng the LD bios in the HuCard slot. 2025-09-22 13:23:47 +01:00
Luke Usher 74a561f62e pc-engine-cd: clarify 'arcade card' and 'system card 3.0' are the same bios rom. 2025-09-22 10:46:42 +01:00
Roger Sanders 52acac2933 ld: Added hash for NEC PAC-N10 bios 2025-09-22 07:46:21 +01:00
Dragorn421 9830daef91 Review: waitGDB -> awaitGDBClient, rename "Launch Debugger" to "Launch Tracer" 2025-09-21 09:39:28 +01:00
Dragorn421 2f9f7670da Add "Wait GDB" boot option 2025-09-21 09:39:28 +01:00
Luke Usher 808aaaf053 Revert "ps1: use physical addresses as early as possible"
This reverts commit 325c0ed876.
2025-09-19 22:19:26 +01:00
Luke Usher 1044d0ad37 desktop-ui: fix settings.bml loading/saving
This was broken by the renaming of the laseractive cores, because () are not valid bml node name characters.
2025-09-19 22:14:50 +01:00
invertego 0ebd9e3bbe ps1: use constant random seed in homebrew mode 2025-09-19 21:37:43 +01:00
invertego 57d1a2ef9a ps1: randomly initialize memory on boot
Randomly initialize CPU RAM, CPU I-cache, CPU scratchpad, GPU VRAM, and
SPU RAM.
2025-09-19 21:37:43 +01:00
Luke Usher eeacac8749 pcd: fixing the build after #2220 2025-09-19 14:13:04 +01:00
Giovanni Bajo 9e1ff7b479 stdc++: reindent 2025-09-19 12:49:19 +01:00
Giovanni Bajo 32d2f3d2b2 stdc++: completely remove nall::vector, now unused 2025-09-19 12:49:19 +01:00
Giovanni Bajo c64aff5992 stdc++: nall: remove vector<string> specialization (not used anymore) 2025-09-19 12:49:19 +01:00
Giovanni Bajo 3390d66a7e stdc++: migrate tools/tests removing uses of nall::vector 2025-09-19 12:49:19 +01:00
Giovanni Bajo e388299f05 stdc++: nall: remove other nall::vector usages 2025-09-19 12:49:19 +01:00
Giovanni Bajo f31fa5c99f stdc++: nall: migrate more uses to std::vector 2025-09-19 12:49:19 +01:00
Giovanni Bajo fec8d9029c stdc++: nall: remove some uses of nall::vector 2025-09-19 12:49:19 +01:00
Giovanni Bajo c4bc76b219 stdc++: avoid nall::vector in implementation of split functions 2025-09-19 12:49:19 +01:00
jcm 7d91e5f38a CI: avoid Strawberry Perl Ccache installation 2025-09-19 12:49:00 +01:00
jcm 907ccf6494 build: Clarify when to build genius 2025-09-19 12:49:00 +01:00
jcm c7fabe82d6 build: Remove /permissive- (unneeded under C++20) 2025-09-19 12:49:00 +01:00
jcm 9f9ff6bf09 build: disable IPO for *nix CI builds 2025-09-19 12:49:00 +01:00
jcm f60c003826 build: Don't use unsupported option in Clang-CL 2025-09-19 12:49:00 +01:00
jcm 6a30f98145 build: move generated targets to work around Visual Studio 2025-09-19 12:49:00 +01:00
Luke Usher 7855c8b469 desktop-ui: group mega ld/pc-engine ld as Pioneer LaserActive 2025-09-19 12:29:00 +01:00
Roger Sanders ee85afd30c ld: Initial working version of NEC PAC support for the LaserActive 2025-09-19 10:35:55 +01:00
Roger Sanders 09932f11d5 ld: MegaLD emulation accuracy and speed improvements 2025-09-19 10:35:55 +01:00
Luke Usher 85afab5b36 mia: fix fds loading 2025-09-18 10:13:48 +01:00
Giovanni Bajoandjcm 75ef6810e2 stdc+: switch to nall::split_and_strip and apply review suggestions
Co-authored-by: jcm <[email protected]>
2025-09-16 06:42:29 +01:00
Giovanni Bajo 66db5eb88c stdc++: discard global namespace qualifier for nall everywhere 2025-09-16 06:42:29 +01:00
Giovanni Bajo d5c3a4805b stdc++: apply review suggestions 2025-09-16 06:42:29 +01:00
Giovanni Bajo 82c777e7c2 stdc++: hiro: fix qt backend build 2025-09-16 06:42:29 +01:00
Giovanni Bajo cdbc88f92e stdc++: ruby: fix freebsd build 2025-09-16 06:42:29 +01:00
Giovanni Bajo 970a019476 stdc++: nall::string remove non-const constructors to avoid problematic uses 2025-09-16 06:42:29 +01:00
Giovanni Bajo 9c9ba5d6f4 stdc++: nall: remove string::split and vector<string>::match 2025-09-16 06:42:29 +01:00
Giovanni Bajo 86790da2ec stdc++: nall: finish migrating string split/match methods to functions 2025-09-16 06:42:29 +01:00
Giovanni Bajo 7fff423649 stdc++:: add global nall::split/match functions, migrate part of the code 2025-09-16 06:42:29 +01:00
Giovanni Bajo d258228cc0 md: avoid including dc-removal.hpp within the ares::MegaDrive namespace 2025-09-16 06:42:29 +01:00
Giovanni Bajo 9bf3ffc3ae stdc++: finish mia migration 2025-09-16 06:42:29 +01:00
Giovanni Bajo 7168f2e411 stdc++: migrate part of mia to std::vector 2025-09-16 06:42:29 +01:00
Giovanni Bajo c75ad74ce0 stdc++: desktop-ui: migrate from nall::vector to std::vector
- 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
2025-09-16 06:42:29 +01:00
Giovanni Bajo 7ed8d6feac cmake: disable build of optional targets in ubuntu-ci-qt
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).
2025-09-16 06:42:29 +01:00
tykkiman e2bf15a6ce recompiler: remove static_assert(false) from a template
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.
2025-09-15 18:55:06 +01:00
Jay Prewitt 29139b104c n64: Use ISV read pointer as a start address 2025-09-15 18:54:17 +01:00
tykkiman 0b2a85f803 n64: use faster host function calls in the recompiler
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.
2025-09-14 21:20:30 +01:00
tykkiman a55688a95d recompiler: optimized 64-bit System V function calls
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.
2025-09-14 21:20:30 +01:00
Jay Prewitt f39ca5e3a7 n64: Make MI repeat mode accurate for 1 and 2 byte writes 2025-09-12 11:30:05 +01:00
jcmandStefan Schlosser 1a2aedcf00 CI: Add FreeBSD runner
Co-authored-by: Stefan Schlosser <[email protected]>
2025-09-09 17:09:21 +01:00
jcm 05e9c3a6c9 CI: Add Qt build 2025-09-09 17:09:21 +01:00
Christopher Bonhage 0d9ce81d20 Implement N64 Bio Sensor accessory 2025-09-09 14:06:34 +01:00
Christopher Bonhage eed44e0012 Support for N64 accessory commands with non-standard data lengths 2025-09-09 14:06:34 +01:00
Christopher Bonhage 93073f2700 Implement N64 accessory DETECT controller status 2025-09-09 14:06:34 +01:00
jcm 53a08c9101 build: Fix framework bundle copies under non-Xcode generators on macOS 2025-09-09 12:11:23 +01:00
jcm 6540059a28 build: Don't use -fno-char8_t when compiling C 2025-09-09 12:11:23 +01:00
jcm 48c816f2f9 desktop-ui: Properly initialize rewind state on startup 2025-09-09 12:11:07 +01:00
User 1edb30d1ea gba: improve handling of MEMCNT register 2025-09-08 14:34:10 +01:00
Jay Prewitt 797c798787 n64: Implement basic MI repeat mode
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.
2025-09-08 14:33:59 +01:00
Giovanni Bajo 2c3341dfdf stdc++: finish migrating ares 2025-09-08 14:32:44 +01:00
Giovanni Bajo 31357eb4e5 stdc++: bulk migration of ares 2025-09-08 14:32:44 +01:00
Giovanni Bajo 3401322e6e stdc++: migrate node and debuggers 2025-09-08 14:32:44 +01:00
Giovanni Bajo 50ed2ba9bc stdc++: replace vector<string>.merge macros with nall::merge; keep nall::vector path ops; add initializer_list overload 2025-09-08 14:32:44 +01:00
Giovanni Bajo ff8bdbcdc6 stdc++: add vector-helpers merge/split; migrate includes; use merge() in N64 disassemblers; std::vector<string> split 2025-09-08 14:32:44 +01:00
Giovanni Bajo 935802da1a stdc++: migrate enumerate() to std::vector<string> 2025-09-08 14:32:44 +01:00
Roger Sanders 1dffa3d974 nall: Fix linux-only compilation issue with owning string_view removal 2025-09-05 06:47:30 +01:00
Roger Sanders 78144f5fab nall: fixed remaining string_view conversion cases from release builds 2025-09-05 06:47:30 +01:00
Roger Sanders 47aa5dc1df nall: string_view missing change fix no2 2025-09-05 06:47:30 +01:00
Roger Sanders bf7a1a205c nall: Fixed a missing change 2025-09-05 06:47:30 +01:00
Roger Sanders 96bd51471d nall: remove memory ownership from string_view again 2025-09-05 06:47:30 +01:00
Giovanni Bajo bbd9fcca0c hiro: fix undefined behavior converting negative coordinates to u32
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.
2025-09-04 11:10:42 +01:00
Giovanni Bajo f263e89f06 nall: remove unused modules 2025-09-03 19:48:57 +01:00
User 698ea74132 gba: fix remaining C++20 deprecation warnings 2025-09-02 22:04:44 +01:00
Giovanni Bajo 766fc1ece2 stdc++: remove all instances of if statements with initializers 2025-09-02 22:04:32 +01:00
Giovanni Bajo 247dd180ce stdc++: fixes from review 2025-09-02 22:04:32 +01:00
Giovanni Bajo 23ed3de93c stdc++: hiro: revert changes to clear of subwidgets that were broken 2025-09-02 22:04:32 +01:00
Giovanni Bajo c0791baa3d stdc++: simplify some code via std::erase 2025-09-02 22:04:32 +01:00
Giovanni Bajo 9ad89d134e stdc++: use range syntax in more places 2025-09-02 22:04:32 +01:00
Giovanni Bajo 84ce0e3d9f stdc++: convert all sorts and reverse loops to ranges 2025-09-02 22:04:32 +01:00
Giovanni Bajo 92fe0d2e44 stdc++: Introduce range-helpers and nall::index_of. 2025-09-02 22:04:32 +01:00
Giovanni Bajo 864ca3d91e stdc++: C++20 compactness pass (branch-local):
- 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).
2025-09-02 22:04:32 +01:00
Giovanni Bajo 8729c5f591 stdc++: array_view: remove redundant explicit constructions where implicit std::vector conversion works (Pak append callers, vfs cdrom, emulator firmware, BWT/LZSA). Keep explicit array_view only when required for string construction or subspan. 2025-09-02 22:04:32 +01:00
Giovanni Bajo 89be74aab5 stdc++: Apply changes from review 2025-09-02 22:04:32 +01:00
Giovanni Bajo 24c5e367cc stdc++: Fix CI: map remaining vector-only APIs to std::vector equivalents: gtk keyboard keycodes push_back; windows menu-bar use erase/push_back and clear; WASAPI/XAudio2/WaveOut: use std algorithms and front()/empty() instead of vector truthiness/first/find; compute indices explicitly. 2025-09-02 22:04:32 +01:00
Giovanni Bajo 5004ca4a33 stdc++: hiro gtk/qt: migrate remaining nall::vector usages to std::vector; map append/remove/reset; update keyboard polling and settings containers; fix window lists to use std::vector ops. 2025-09-02 22:04:32 +01:00
Giovanni Bajo 799d0ce726 stdc++: tests: minimal changes to make tests building 2025-09-02 22:04:32 +01:00
Giovanni Bajo 47348d9002 stdc++: hiro/windows: replace nall::vector with std::vector; map append/remove/reset; fix utilities/keyboards/timer APIs; guard DropPaths and pixel buffers accordingly. 2025-09-02 22:04:32 +01:00
Giovanni Bajo 3eeecf1cc2 stdc++: Fix CI: std::vector<bool> copy; BrowserDialog truthiness; replace remaining .append/remove/reset in joypad/combo/icon-view; GTK TabFrame tabs as std::vector; ALSA/OSS device selection via std algorithms; fix reverse iteration and setSelected signature. 2025-09-02 22:04:32 +01:00
Giovanni Bajo 31380a1976 stdc++: ruby: migrate nall::vector to std::vector; mechanical API alignment
- Replace nall::vector with std::vector across ruby (audio/input) and hiro glue; update overrides to std::vector.

- Map vector APIs: append/reset/remove/truthiness -> push_back/clear/erase/empty(); adjust DropPaths guards and BrowserDialog callers.

- Fix Windows/GTK fallout: DropPaths checks and Windows TableView indexing; Keyboard::poll returns std::vector<bool>.

- Source-only commit; excludes build outputs and submodules.
2025-09-02 22:04:32 +01:00
Giovanni Bajo 6974764393 stdc++: std::vector alignment across nall/ruby/hiro; remove nall::vector-only APIs
- nall/directory (Windows): return std::vector<string>; replace list.append with push_back; convert drive split to std::vector
- ruby audio/video/input: make virtual overrides return std::vector; replace .append with .push_back; poll() now uses std::vector for device lists
- hiro utilities (cocoa/gtk/qt/windows): DropPaths now returns std::vector<string>; replace .append with .push_back; guard empty paths on GTK
- hiro widgets: tab-frame reordering uses erase/insert instead of take(); console history uses std::vector ops; table-view selection uses std::vector<u32>
- string: add stringify<std::vector<string>> for toolchains that instantiate it indirectly

No semantic changes intended; local build verified with ninja.
2025-09-02 22:04:32 +01:00
Giovanni Bajo 0e73ba0cc1 stdc++: nall: std::vector compatibility across toolchains
- 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.
2025-09-02 22:04:32 +01:00
Giovanni Bajo 5bb5a70b0c stdc++: std::vector migration and interop cleanup across mia/desktop-ui
- 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.
2025-09-02 22:04:32 +01:00
Giovanni Bajo 2830ab92f7 stdc++: nall: remove most uses of nall::vector from the library and adapt callers
- 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).
2025-09-02 22:04:32 +01:00
Giovanni Bajo 2eb0e677a8 stdc++: Migrate project off nall::vector (outside nall) to std::vector
Scope
- Replace nall::vector with std::vector across hiro, ruby, and desktop-ui.
- Remove external includes of <nall/vector.hpp>; keep nall/ self-includes unchanged.

API adaptations
- append/prepend -> push_back/insert(begin,...).
- remove/removeLeft/removeRight -> erase/erase(begin)/erase(end-1) as appropriate.
- take*/first/last/left/right -> front()/back() or index-based access.
- contains/find/findSorted/foreach -> std::find, std algorithms, or range loops.
- reverse(...) iterations -> rbegin()/rend() or explicit reverse-iterator loops.
- vector truthiness -> use empty()/size() checks.

Subsystem-specific changes
- Ares node registry: use std::vector for class lists and child nodes; replace find/append/remove usage.
- Debug facility: store notices in std::vector; dedup via std::find.
- Hiro widgets/layouts: convert container state to std::vector; update signatures (e.g., onDrop/doDrop to std::vector<string>);
  fix batch/selection helpers to build std::vector results; update menu/popup/combo/table/tree widgets accordingly.
- Cocoa/GTK integrations: adjust DropPaths usage and emptiness checks.
- Ruby backends (audio/video/input): change capability lists and device enumerations to std::vector; replace .first() with front()
  and .append() with push_back; fix OpenAL/SDL/driver helpers.
- Desktop UI: Program::screens/streams now std::vector; platform attach/detach uses erase+remove; message queue uses std::vector
  push_back + pop-front pattern; Presentation drop handler accepts std::vector<string>.
- Message/Browser dialogs: std::vector for button/options/filters; remove truthiness; use back()/empty().

Build
- Verified clean build for desktop-ui, hiro, and ruby after changes (ninja).

Notes
- Conservative migration: no changes inside nall/ itself (still ships its own vector for internal use).
- Follow-up work can progressively replace remaining nall containers/APIs as needed.
2025-09-02 22:04:32 +01:00
John Chadwick a5f5eccdbe hiro/qt: Add Qt 6 support
Basic functionality is tested and working great. Obviously, things do
not work in Wayland yet.
2025-09-01 20:33:41 +01:00
John Chadwick 82ff8dbf6b hiro/qt: QLayout::setMargin -> QLayout::setContentsMargins
setMargin has been obsolete since Qt 4.3!
2025-09-01 20:33:41 +01:00
John Chadwick c9d8fc525c hiro/qt: Use QScreen for Monitor
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.
2025-09-01 20:33:41 +01:00
John Chadwick 3854a4561d hiro/qt: Remove pendingEvents, add timeout to processEvents
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.
2025-09-01 20:33:41 +01:00
John Chadwick cf4afeb7f0 hiro/core: Remove Application::pendingEvents
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.
2025-09-01 20:33:41 +01:00
John Chadwick 755e15c3e1 Use QScreen for Desktop::{size,workspace}
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.)
2025-09-01 15:51:27 +01:00
John Chadwick 7f0d020466 Remove Qt 4 support.
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.
2025-09-01 15:47:36 +01:00
User 5a2be88f41 gba: fix some warnings from C++20 deprecating bitwise operations between different enums 2025-08-31 11:42:24 +01:00
jcm be570117bb CI: overwrite built-in pinned CMake installation 2025-08-30 16:31:42 +01:00
User 640fe5722c gba: handle cartridge access sizes via CPU bus 2025-08-30 15:35:57 +01:00
jcm dff1ad01a6 build: Disable C++20 module scanning 2025-08-29 23:58:11 +01:00
jcm e7a00354dc build: Add -fno-char8_t and /Zc:char8_t- 2025-08-29 16:14:23 +01:00
jcm f042f7a51a build: Compile in C++20 mode 2025-08-29 16:14:23 +01:00
jcm 4d92a5b433 Do not rely on implicit capture of this in lambdas 2025-08-29 16:14:23 +01:00
User 4aed87bf45 fc: bit 5 of $4015 reads open bus 2025-08-29 13:58:01 +01:00
User a5e76e2e4e mos6502: fix JSR memory transactions 2025-08-29 13:58:01 +01:00
User c7277c964e mos6502: general cleanup 2025-08-29 13:58:01 +01:00
jcm 846b622c80 build: Run gersemi formatting pass 2025-08-29 13:57:23 +01:00
jcm abcdff3e60 build: Fix list/string conversion in component list 2025-08-29 13:57:23 +01:00
jcm 4fcfe3a485 build: Clean up miscellaneous target locations 2025-08-29 13:57:23 +01:00
jcm 76b0204d91 build: Clean up link relationships
mame2bml: Fix linking

mia-ui: Fix linking

dekstop-ui: Fix linking
2025-08-29 13:57:23 +01:00
jcm cac6f0534a Update CMake policy version 2025-08-29 13:57:23 +01:00
jcm f66bb568df build: Match libco source organization with other targets 2025-08-29 13:57:23 +01:00
jcm cc4556824e build: Update .gersemirc for newer gersemi version 2025-08-29 13:57:23 +01:00
jcm c6f7efb797 build: Remove/fix up various unused/extraneous build code 2025-08-29 13:57:23 +01:00
jcm 6a2fcb21dc hiro: Make backend definition public 2025-08-29 13:57:23 +01:00
jcm 2b347c65de build: Track project meta files in IDEs 2025-08-29 13:57:23 +01:00
jcm f1823630be build: Update dependencies
deps.windows: Update SDL to 3.2.20
Update slang-shaders to ref `c9303dc`
deps.macos: Update SDL to 3.2.20
deps.macos: Update MoltenVK to 1.4.0
2025-08-29 13:57:13 +01:00
Christopher Bonhage 41d1b7e57d Fix Controller "Nothing" checked state in portMenu 2025-08-26 09:40:01 +01:00
invertego c28ba81684 Revert "nall: clean up string conversions in cue/mmi decode"
This reverts commit 81dea4cf7e.
2025-08-26 09:39:42 +01:00
invertego 1561a1d0b4 Revert "nall: remove memory ownership from string_view"
This reverts commit 70fa70fff4.
2025-08-26 09:39:42 +01:00
jcm 0a302dcf0e desktop-ui: Create program guard for system menu items 2025-08-23 20:25:26 +01:00
TascoDLX 07051ab738 desktop-ui: avoid overwriting paused status message 2025-08-23 19:39:31 +01:00
jcm 973030ab67 ares: Set up color settings before calling colors() 2025-08-23 19:39:00 +01:00
jcm 67716bcedf hiro/cocoa: Don't autoenable menu items 2025-08-22 12:40:07 +01:00
Giovanni Bajo e06b748516 n64: activate pak menu on all four controllers 2025-08-22 11:16:13 +01:00
remutro 02dac5b4b7 Update controller pak menues for the N64 2025-08-22 08:30:17 +01:00
jcm a4b8571b61 desktop-ui: remove Apply buttons from driver settings 2025-08-21 14:25:51 +01:00
Roger Sanders a3fa22b5fc ld: Revert palette nullptr check 2025-08-21 14:25:45 +01:00
Roger Sanders 9e9b6f8642 ld: Apply a pixel offset patch to fix alignment under H40 mode 2025-08-21 14:25:45 +01:00
Roger Sanders 5f6a0983bd ld: Fixed some stop point resume and image blanking behaviour 2025-08-21 14:25:45 +01:00
Roger Sanders 2fcab5ca5f ld: Fix overscan mode, and address some redraw issues. 2025-08-21 14:25:45 +01:00
jcm 778a32700d screen: consistently refresh palette after reset() 2025-08-20 12:33:43 +01:00
Luke Usher a6577318b6 md: bump save state version 2025-08-19 13:57:24 +01:00
Roger Sanders badd476d3b ld: Fixed a double buffering issue which caused single-frame errors 2025-08-19 13:56:36 +01:00
Roger Sanders 5a3548402b ld: Fixed several aspects of video disable and stop point behaviour 2025-08-18 15:42:20 +01:00
User c1f0307a8d gba: allow running DMA during CPU idle cycles 2025-08-17 22:30:04 +01:00
Roger Sanders 77c0718df4 ld: Convert video composition to use 16.16 fixed point for a 3x speedup 2025-08-17 16:00:42 +01:00
Roger Sanders 30bff8dd06 ld: Cleaned up version of video compositing prior to optimization 2025-08-17 16:00:42 +01:00
Roger Sanders b1cf9bf4e5 ld: Added support for remaining analog audio mixing features 2025-08-17 07:52:41 +01:00
Roger Sanders bafc2b6ef4 ld: Fixed a potential out of bounds array index issue in the previous commit 2025-08-16 06:31:39 +01:00
Roger Sanders 565591568f ld: Fixed a few disc side changing issues 2025-08-16 06:31:39 +01:00
Roger Sanders 9df891606f ld: Removed region blocks for now since titles appear region free 2025-08-16 00:43:31 +01:00
Roger Sanders eea666317b ld: Fixed incorrect alignment of CLV seek operations. Improved media detection. 2025-08-16 00:43:31 +01:00
Luke Usher ceff1d47a6 ld: preliminary support for multi-disc/multi-side titles
Mostly untested, but verified going from "Disc 1 side 1" to "No Disc" to "Disc 1 Side 1" again in the bios works as expected.
2025-08-15 12:58:47 +01:00
invertego 81dea4cf7e nall: clean up string conversions in cue/mmi decode
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.
2025-08-14 08:56:08 +01:00
jcmandkev4cards 17fa3b58a6 desktop-ui: Fix hotkey behavior when unfocused
Co-authored-by: kev4cards <[email protected]>
2025-08-14 07:46:11 +01:00
invertego 70fa70fff4 nall: remove memory ownership from string_view
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.
2025-08-14 07:45:14 +01:00
Roger Sanders 137afe5b5b ld: Fix memory issues with MegaLD games after merge. Some additional cleanup. 2025-08-14 07:44:37 +01:00
Luke Usher 545790f048 Revert "nall: in priority-queue, call event callbacks with correct timing"
This reverts commit 6992197fb8.
2025-08-13 17:34:12 +01:00
Luke Usher 807ef03005 Revert "n64: improve PI DMA accuracy with stricter timings"
This reverts commit bea395b24b.
2025-08-13 17:34:12 +01:00
Luke Usher ce89a31749 ld: pass system type through a pak attribute 2025-08-13 17:25:28 +01:00
Luke Usher 3e7675cafb ld: pass location through a pak attribute 2025-08-13 17:25:23 +01:00
Luke Usher 4132375f26 desktop-ui: fix a crash when opening the settings dialog from the "missing firmware" prompt 2025-08-13 17:25:17 +01:00
Luke Usher 5e0bd5b3b8 ld: nall-ize mmi; remove nlohmann/json
Likely still room for improvement; especially if multi-side games exist, but that's a later problem.

mia: minor cleanups/nallisms
2025-08-13 17:25:11 +01:00
Luke Usher d00c84ff1b mia: add laserdisc medium type 2025-08-13 17:25:06 +01:00
Luke Usher 97f3a7a6fb thirdparty: fix qoi/qon build on all platforms 2025-08-13 17:25:00 +01:00
Roger Sanders 8c656cdfd3 mld: Initial MegaLD support based on a skeleton by Luke Usher 2025-08-13 17:24:54 +01:00
Giovanni Bajo bea395b24b n64: improve PI DMA accuracy with stricter timings
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.
2025-08-12 14:09:16 +01:00
Giovanni Bajo 6992197fb8 nall: in priority-queue, call event callbacks with correct timing
This allows callbacks for repeated events (rescheduled at each callback)
to not have additional latency caused by the latency with which we call
step().
2025-08-12 14:09:16 +01:00
Giovanni Bajo 097698ab63 n64: support configuration of different paks via homebrew header
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.
2025-08-12 14:08:59 +01:00
Giovanni Bajo 46abceebf5 n64: fix controller pak formatting
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.
2025-08-08 09:03:54 +01:00
Giovanni Bajo 06130778b7 n64: fix readback of PI_CART_ADDR after direct I/O 2025-08-06 15:51:22 +01:00
jcm 85b8d6c5a5 nall: Dynamically load SetThreadDescription on Windows 2025-08-06 08:57:28 +01:00
Luke Usher 8436634bc1 desktop-ui: remove "Fixed" and "Pixel Perfect" scale factors
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.
2025-07-29 10:12:10 +01:00
Giovanni Bajo 5972b4e1aa Implement aspect correction mode
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.
2025-07-29 09:45:52 +01:00
jcm 426606bd02 desktop-ui: Defer settings window initialization on startup 2025-07-27 19:04:22 +01:00
Giovanni Bajo f9604e29e6 n64: correctly render full resolution on PAL
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.
2025-07-27 19:04:12 +01:00
jcm 7d7b8ea4b2 n64: Reinitialize paraLLEl-RDP on system reset 2025-07-23 15:52:10 +01:00
remutro 2ed529d564 Fix mouse capture on Windows devices 2025-07-23 13:35:56 +01:00
clippy 73148db456 prevent 64 bit access to RCP over gdb 2025-07-23 13:35:37 +01:00
User 2fbc9c391c arm7tdmi: fix cycle order for SWP instruction 2025-07-23 11:29:10 +01:00
png183 12f3d6d89d gba: add comments to clarify how the upper 8 bits of SIOMLT_SEND are used 2025-07-23 11:28:42 +01:00
User 78c13dddef gba: SIOMLT_SEND should be a 16-bit register 2025-07-23 11:28:42 +01:00
Luke Usher be19b58307 sfc: add support for Limited Run Games SNES rumble specification.
See https://github.com/LimitedRunGames-Tech/snes-rumble
2025-07-21 13:09:30 +01:00
jcm bca80dc784 desktop-ui: Make internal program methods private; add docstrings 2025-07-20 19:38:22 +01:00
jcm e6fe07b084 desktop-ui: Fix undefined behavior in exit handler 2025-07-20 19:38:22 +01:00
jcm c28e47cb93 deps: Update dependencies to 2025-07-14 release 2025-07-15 12:38:57 +01:00
jcm c217662211 desktop-ui: Prevent deadlock when exiting 2025-07-14 14:49:40 +01:00
jcm 975a35e7a7 build: Provide librashader header path hint on all OSs 2025-07-14 10:38:40 +01:00
jcm 2e9233e534 CI: Ignore signing errors on Windows 2025-07-14 10:38:21 +01:00
jcm 4c6d151f7f build: Statically link runtime library for Windows CI builds 2025-07-14 10:38:13 +01:00
invertego 383931bde9 build: remove extraneous msvc optimization flags
/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.
2025-07-14 10:37:55 +01:00
TascoDLX 1ac8c602c9 ms: remove obsolete screen resize code 2025-07-13 15:31:15 +01:00
Giovanni Bajo d5135ca35f n64: improve gdb memory hooks
Now support reads and writes of arbitrary lengths in both RDRAM
and RCP ares (using respectively 8-bit and 32-bit accesses).
2025-07-13 15:30:52 +01:00
User 8265726879 gba: prefetcher cannot be read when R15 is misaligned 2025-07-12 13:43:20 +01:00
User 5261757f3c gba: prefetcher should not be marked full if read on the same cycle that it was filled 2025-07-12 13:43:20 +01:00
Luke Usher c099be2b85 pce: force enable Pixel Accuracy VDP
The scanline renderer in this case is too buggy and causes too many game issues at this time.
2025-07-10 19:27:26 +01:00
jcm de8143ef47 CI: Upload source archives with releases 2025-07-10 18:24:30 +01:00
jcm b80f08956b build: Fix ARES_VERSION_OVERRIDE in source archives 2025-07-10 18:24:30 +01:00
kev4cards a3088f6d4c node, n64, ps1: rework ps1 stick into a virtual square, adjust scaling for N64 stick, and move common code into Node::Input::Axis 2025-07-10 10:08:06 +01:00
jcm fdaf0b65a1 build: Run gersemi CMake formatting pass 2025-07-10 10:06:03 +01:00
jcm 71e0ad1f5b build: Improve build code for test harnesses 2025-07-10 10:06:03 +01:00
User c87be1b4f0 gba: more prefetcher timing improvements 2025-07-10 10:05:42 +01:00
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
6416 changed files with 78890 additions and 774480 deletions

No files matched your search

-3
View File
@@ -1,11 +1,8 @@
# 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
+31
View File
@@ -0,0 +1,31 @@
# dummy GitHub target used to enable editing of GitHub files within generated IDE projects
add_library(.github INTERFACE)
set(.github_sources
ISSUE_TEMPLATE/bug_report.md
ISSUE_TEMPLATE/feature_request.md
ISSUE_TEMPLATE/game-issue-report.md
scripts/build_macos.sh
scripts/build_ubuntu.sh
scripts/build_windows.sh
scripts/package_artifacts.sh
workflows/build-aux.yml
workflows/build.yml
workflows/pr.yml
workflows/push.yml
workflows/release.yml
)
target_sources(
.github
PRIVATE
${.github_sources}
../.gitignore
../.gitattributes
../README.md
../LICENSE
)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${.github_sources})
+1
View File
@@ -10,6 +10,7 @@ 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
+1 -1
View File
@@ -13,7 +13,7 @@ cmake --preset $TARGET_PRESET
pushd build
cmake --build . --config RelWithDebInfo
if [ "$CROSS_COMPILE" = true ]; then
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/
+8 -4
View File
@@ -21,13 +21,12 @@ do
mkdir ${outdir}-dSYMs
cp -a ${bindir}/ares-${package}-dSYMs/*.dSYM ${outdir}-dSYMs
cp -a ${bindir}/ares-${package}/*.app ${outdir}
zip -r ../ares-${package}.zip ${outdir}
zip -r ../ares-${package}-dSYMs.zip ${outdir}-dSYMs
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-x64 windows-clang-cl-arm64
for package in windows-x64 windows-clang-cl-arm64
do
mkdir "${package}"
cd "${package}"
@@ -43,3 +42,8 @@ do
zip -r ../ares-${package}.zip ${outdir}
cd -
done
# Package the source archive
pushd src
git archive --format=tar.gz -o ../ares-source.tar.gz HEAD
popd
+132
View File
@@ -0,0 +1,132 @@
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: ubuntu-gcc-arm64-qt
os: ubuntu-24.04-arm
shell: bash
target-cmake-preset: ubuntu-ci-qt
- name: freebsd
os: ubuntu-24.04
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' && matrix.platform.name != 'freebsd'
run: |
sudo apt-get update -y -qq
sudo apt-get install cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev qt6-base-dev
- name: "Build: Linux"
if: runner.os == 'Linux' && matrix.platform.name != 'freebsd'
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: "Build: FreeBSD"
if: matrix.platform.name == 'freebsd'
uses: cross-platform-actions/action@492b0c80085400348c599edace11141a4ee73524
env:
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
with:
operating_system: freebsd
version: '15.0'
environment_variables: TARGET_PRESET
run: |
sudo pkg install -y cmake pkgconf ccache ninja gtk3 libX11 libXext libXrandr libXrender libglvnd alsa-lib libao libudev-devd librashader openal-soft pulseaudio sdl3 vulkan-loader
.github/scripts/build_ubuntu.sh
- 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/*
+82 -264
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,53 +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
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: 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:
@@ -67,250 +49,86 @@ 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: |
sudo xcode-select -s /Applications/Xcode_16.1.0.app/Contents/Developer
export MACOSX_DEPLOYMENT_TARGET=10.13
brew install ninja cmake
pip install --no-input setuptools
rustup toolchain install nightly
rustup default nightly
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
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 uninstall --ignore-dependencies cmake
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
continue-on-error: true
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'
folder: 'build/desktop-ui/rundir/'
timestampUrl: 'http://timestamp.digicert.com'
- name: "macOS: notarize"
if: false
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
- 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: false
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-universal/ares.app/Contents/MacOS/ares
for package in windows windows-msvc-arm64 macos-universal
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-universal
uses: actions/upload-release-asset@v1
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-macos-universal.zip', asset_name: 'ares-macos-universal.zip', asset_content_type: 'application/zip' }
# - name: Upload ares-ubuntu
# uses: actions/upload-release-asset@v1
# env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
# with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-ubuntu.zip', asset_name: 'ares-ubuntu.zip', asset_content_type: 'application/zip' }
name: ${{ matrix.program }}-${{ matrix.platform.name }}-dSYMs
path: build/dSYMs/*
-153
View File
@@ -1,153 +0,0 @@
name: Build (New)
on:
workflow_call:
inputs:
codesign:
description: Enable codesigning
required: false
default: false
type: boolean
jobs:
build:
strategy:
fail-fast: false
matrix:
program:
- ares
config:
- RelWithDebInfo
platform:
- name: windows-x64
os: windows-latest
compiler: clang++
shell: 'msys2 {0}'
msystem: clang64
install: mingw-w64-clang-x86_64-clang
target-cmake-preset: windows-ci-mingw-native
- name: windows-x64-gcc
os: windows-latest
compiler: g++
shell: 'msys2 {0}'
msystem: mingw64
install: mingw-w64-x86_64-toolchain
target-cmake-preset: windows-ci-mingw-native
- name: windows-clang-cl-x64
os: windows-latest
windres: rc
shell: bash
target-cmake-preset: windows-ci-cl-native
- name: windows-clang-cl-arm64
os: windows-latest
windres: rc
shell: bash
target-cmake-preset: windows-ci-cl-cross
native-cmake-preset: windows-ci-cl-native
- name: windows-msvc-x64
os: windows-latest
windres: rc
shell: bash
target-cmake-preset: windows-ci-msvc-native
- name: windows-msvc-arm64
os: windows-latest
windres: rc
shell: bash
target-cmake-preset: windows-ci-msvc-cross
native-cmake-preset: windows-ci-msvc-native
- name: macos-universal
os: macos-15
compiler: clang++
shell: sh
install: cmake ccache xcbeautify
target-cmake-preset: macos-ci-universal
- name: ubuntu
os: ubuntu-latest
compiler: g++
shell: bash
install: cmake ccache ninja-build libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
target-cmake-preset: ubuntu-ci
name: ${{ matrix.program }}-${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
defaults:
run:
shell: ${{ matrix.platform.shell }}
steps:
- name: Install MSYS2 Dependencies
if: matrix.platform.shell == 'msys2 {0}'
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.platform.msystem }}
install: make git cmake ccache ninja ${{ matrix.platform.install }}
- name: "macOS: Import Certificate"
if: runner.os == 'macOS' && inputs.codesign
uses: apple-actions/import-codesign-certs@v3
continue-on-error: ${{ !inputs.codesign }}
with:
p12-file-base64: ${{ secrets.MACOS_CERTIFICATE_DATA }}
p12-password: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
- name: Checkout source code
uses: actions/checkout@v4
with:
fetch-tags: true
fetch-depth: 0
- name: Install Linux Dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update -y -qq
sudo apt-get install ${{ matrix.platform.install }}
- name: Install macOS Dependencies
if: runner.os == 'macOS'
run: |
brew install ${{ matrix.platform.install }}
- name: "Build: Linux"
if: runner.os == 'Linux'
run: .github/scripts/build_ubuntu.sh
env:
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
- name: "Build: Windows"
if: runner.os != 'macOS' && runner.os != 'Linux'
run: .github/scripts/build_windows.sh
env:
CROSS_COMPILE: ${{ matrix.platform.native-cmake-preset != '' }}
NATIVE_PRESET: ${{ matrix.platform.native-cmake-preset }}
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
- name: "Windows: sign"
if: runner.os == 'Windows' && inputs.codesign
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
with:
certificate: '${{ secrets.WIN_CERTIFICATE }}'
password: '${{ secrets.WIN_PASSWORD }}'
certificatesha1: '${{ secrets.WIN_CERTHASH }}'
certificatename: '${{ secrets.WIN_CERTNAME }}'
folder: 'build/desktop-ui/rundir/'
timestampUrl: 'http://timestamp.digicert.com'
- name: "Build: macOS"
if: runner.os == 'macOS'
run: .github/scripts/build_macos.sh
env:
TARGET_PRESET: ${{ matrix.platform.target-cmake-preset }}
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
- name: Upload Build (Windows)
if: runner.os != 'macOS' && runner.os != 'Linux'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}
path: build/desktop-ui/rundir/*
- name: Upload Build (macOS)
if: runner.os == 'macOS'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}
path: build/desktop-ui/RelWithDebInfo/
- name: Upload Debug Symbols (Windows)
if: runner.os != 'macOS' && runner.os != 'Linux'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}-PDBs
path: build/PDBs/*
- name: Upload Debug Symbols (macOS)
if: runner.os == 'macOS'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.program }}-${{ matrix.platform.name }}-dSYMs
path: build/dSYMs/*
+8 -2
View File
@@ -11,7 +11,13 @@ concurrency:
cancel-in-progress: true
jobs:
build-project:
name: Build
uses: ./.github/workflows/build_new.yml
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
+8 -5
View File
@@ -1,8 +1,6 @@
name: Push
on:
push:
branches: [ '*' ]
tags: [ 'v*' ]
push
concurrency:
group: '${{ github.workflow }} @ ${{ github.head_ref || github.ref }}'
cancel-in-progress: true
@@ -10,11 +8,16 @@ permissions:
contents: write
jobs:
build:
name: Build ares
uses: ./.github/workflows/build_new.yml
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
+20 -6
View File
@@ -12,13 +12,22 @@ jobs:
if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
path: 'src'
- name: Download Artifacts
uses: actions/download-artifact@v4
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: |
@@ -48,21 +57,26 @@ jobs:
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:
draft: ${{ github.ref != 'refs/heads/master' }}
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-source.tar.gz
${{ github.workspace }}/ares-macos-universal.zip
${{ github.workspace }}/ares-macos-universal-dSYMs.zip
${{ github.workspace }}/ares-windows-x64.zip
${{ github.workspace }}/ares-windows-x64-PDBs.zip
${{ github.workspace }}/ares-windows-clang-cl-x64.zip
${{ github.workspace }}/ares-windows-clang-cl-x64-PDBs.zip
${{ github.workspace }}/ares-windows-clang-cl-arm64.zip
${{ github.workspace }}/ares-windows-clang-cl-arm64-PDBs.zip
+15 -4
View File
@@ -26,10 +26,10 @@
!CMakeLists.txt
!CMakePresets.json
thirdparty/SDL/SDL
thirdparty/SDL/libSDL2-2.0.0.dylib
desktop-ui/out
desktop-ui/obj
# 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
@@ -38,5 +38,16 @@ 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 Qt generated MOC file
hiro/qt/qt.moc
# 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
+7 -6
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.28...3.30)
cmake_minimum_required(VERSION 3.28...4.1)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake" NO_POLICY_SCOPE)
@@ -8,11 +8,9 @@ include(compilerconfig)
include(defaults)
include(helpers)
add_subdirectory(cmake)
add_subdirectory(thirdparty)
add_subdirectory(nall)
add_subdirectory(nall/nall)
add_subdirectory(libco)
add_subdirectory(ruby)
add_subdirectory(hiro)
@@ -21,7 +19,7 @@ add_subdirectory(hiro)
set(
ARES_CORES
a26 fc sfc sg ms md ps1 pce ng msx cv myvision gb gba ws ngp spec n64
CACHE STRING LIST
CACHE STRING "List of systems to be built by the project"
)
# gersemi: on
@@ -35,7 +33,7 @@ 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)
if(HIRO_BACKEND STREQUAL "GTK3")
add_subdirectory(tools/genius)
else()
target_disable_subproject(genius "genius (database editor)")
@@ -52,4 +50,7 @@ endif()
add_subdirectory(tools/sourcery)
message_configuration()
add_subdirectory(.github)
add_subdirectory(cmake)
return()
+27 -3
View File
@@ -12,7 +12,8 @@
"cacheVariables": {
"ARES_PROFILE_ACCURACY": false,
"ARES_BUILD_LOCAL": true,
"ENABLE_CCACHE": true
"ENABLE_CCACHE": true,
"ARES_BUILD_OFFICIAL": {"type": "BOOL", "value": "$penv{ARES_BUILD_OFFICIAL}"}
}
},
{
@@ -81,7 +82,7 @@
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_OSX_ARCHITECTURES": {"type": "STRING", "value": "x86_64;arm64"},
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "10.13"},
"CMAKE_OSX_DEPLOYMENT_TARGET": {"type": "STRING", "value": "11.0"},
"ARES_CODESIGN_IDENTITY": {"type": "STRING", "value": "$penv{MACOS_CERTIFICATE_NAME}"},
"ARES_CODESIGN_TEAM": {"type": "STRING", "value": "$penv{MACOS_NOTARIZATION_TEAMID}"},
"ENABLE_CCACHE": true,
@@ -101,7 +102,9 @@
"ARES_BUILD_LOCAL": false,
"ARES_BUILD_OPTIONAL_TARGETS": true,
"ARES_UNITY_CORES": true,
"ARES_PRECOMPILE_HEADERS": true
"ARES_PRECOMPILE_HEADERS": true,
"CMAKE_MSVC_RUNTIME_LIBRARY": {"type": "STRING", "value": "MultiThreaded"},
"CMAKE_IGNORE_PATH": {"type": "STRING", "value": "C:/Strawberry/c/bin/"}
}
},
{
@@ -158,10 +161,31 @@
"cacheVariables": {
"CMAKE_BUILD_TYPE": {"type": "STRING", "value": "RelWithDebInfo"},
"ENABLE_CCACHE": true,
"ENABLE_IPO": false,
"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++"
}
},
{
"name": "ubuntu-ci-qt",
"displayName": "Ubuntu CI (arm64, gcc, Qt)",
"description": "Single-arch binary for building on Github Actions",
"inherits": ["ubuntu-ci"],
"cacheVariables": {
"USE_QT6": true,
"ARES_BUILD_OPTIONAL_TARGETS": false
}
}
],
"buildPresets": [
-6
View File
@@ -1,6 +0,0 @@
targets = all clean install uninstall verbose
$(targets):
@$(MAKE) -C desktop-ui $@
.PHONY: $(targets)
+30 -2
View File
@@ -1,7 +1,7 @@
----------------------------------------------------------------------
ares
Copyright (c) 2004-2024 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
@@ -828,4 +828,32 @@ You may add additional accurate notices of copyright ownership.
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.
----------------------------------------------------------------------
----------------------------------------------------------------------
----------------------------------------------------------------------
qoi/qon
Copyright (c) 2025, Roger Sanders
Revised QOI format, achieving higher compression with equivalent performance.
Based on the "Quite OK Image" format for fast, lossless image compression
Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
----------------------------------------------------------------------
+11 -5
View File
@@ -5,6 +5,8 @@
**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,21 +16,19 @@ 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.
Building ares
-------------
Build instructions are available on the ares wiki. See build instructions for:
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)
For legacy Makefile build instructions, see [here](https://github.com/ares-emulator/ares/wiki/Legacy-Build-Instructions).
Command-line options
--------------------
@@ -38,12 +38,18 @@ When started from the command-line, ares accepts a few options.
Usage: ./ares [options] game(s)
--help Displays available options and exit
--version Displays the version string of the application
--terminal Create new terminal window (Windows only)
--fullscreen Start in full screen mode
--pseudofullscreen Start in pseudo full screen mode
--kiosk Start in minimal UI mode (implies --no-file-prompt)
--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)
--settings-file path Specify a settings file override (settings.bml)
--save-state slot Specify a save state slot to load (1-9)
```
The --system option is useful when the system type cannot be auto-detected.
+23 -2
View File
@@ -1,5 +1,7 @@
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)
@@ -19,7 +21,7 @@ if(ARES_PRECOMPILE_HEADERS)
target_precompile_headers(ares PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:ares/ares.hpp>")
endif()
target_link_libraries(ares PUBLIC libco sljit nall)
target_link_libraries(ares PRIVATE libco ares::nall::headers $<$<BOOL:${ARES_ENABLE_CHD}>:chdr-static> PUBLIC sljit)
if(ARES_PROFILE_ACCURACY)
target_compile_definitions(ares PUBLIC PROFILE_ACCURACY)
@@ -29,7 +31,7 @@ endif()
target_sources(
ares
PRIVATE ares/ares.cpp ares/ares.hpp ares/inline.hpp ares/platform.hpp ares/random.hpp ares/types.hpp
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(
@@ -97,6 +99,18 @@ target_sources(
ares/node/video/video.hpp
)
target_sources(
ares
PRIVATE
ares/node/debugger/debugger.hpp
ares/node/debugger/graphics.hpp
ares/node/debugger/memory.hpp
ares/node/debugger/properties.hpp
ares/node/debugger/tracer/tracer.hpp
ares/node/debugger/tracer/instruction.hpp
ares/node/debugger/tracer/notification.hpp
)
if(OS_WINDOWS)
include(cmake/os-windows.cmake)
elseif(OS_MACOS)
@@ -291,6 +305,13 @@ set_source_files_properties(
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
)
-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)
-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
+2 -1
View File
@@ -1,12 +1,13 @@
#pragma once
#include <ares/ares.hpp>
#include <vector>
#include <component/processor/mos6502/mos6502.hpp>
namespace ares::Atari2600 {
#include <ares/inline.hpp>
auto enumerate() -> vector<string>;
auto enumerate() -> std::vector<string>;
auto load(Node::System& node, string name) -> bool;
struct Region {
+8 -8
View File
@@ -19,15 +19,15 @@ auto Cartridge::connect() -> void {
information.region = pak->attribute("region");
information.board = pak->attribute("board");
if(information.board == "Linear") board = new Board::Linear{*this};
if(information.board == "Atari8k") board = new Board::Atari8k{*this};
if(information.board == "Atari16k") board = new Board::Atari16k{*this};
if(information.board == "Atari32k") board = new Board::Atari32k{*this};
if(information.board == "Commavid") board = new Board::Commavid{*this};
if(information.board == "ParkerBros8k") board = new Board::ParkerBros{*this};
if(information.board == "Tigervision") board = new Board::Tigervision{*this};
if(information.board == "Linear") board = std::make_unique<Board::Linear>(*this);
if(information.board == "Atari8k") board = std::make_unique<Board::Atari8k>(*this);
if(information.board == "Atari16k") board = std::make_unique<Board::Atari16k>(*this);
if(information.board == "Atari32k") board = std::make_unique<Board::Atari32k>(*this);
if(information.board == "Commavid") board = std::make_unique<Board::Commavid>(*this);
if(information.board == "ParkerBros8k") board = std::make_unique<Board::ParkerBros>(*this);
if(information.board == "Tigervision") board = std::make_unique<Board::Tigervision>(*this);
if(!board) board = new Board::Interface{*this};
if(!board) board = std::make_unique<Board::Interface>(*this);
board->pak = pak;
board->load();
power();
+1 -1
View File
@@ -22,7 +22,7 @@ struct Cartridge {
//serialization.cpp
auto serialize(serializer&) -> void;
unique_pointer<Board::Interface> board;
std::unique_ptr<Board::Interface> board;
//private:
struct Information {
+1 -1
View File
@@ -20,7 +20,7 @@ auto ControllerPort::unload() -> void {
}
auto ControllerPort::allocate(string name) -> Node::Peripheral {
if(name == "Gamepad") device = new Gamepad(port);
if(name == "Gamepad") device = std::make_unique<Gamepad>(port);
if(device) return device->node;
return {};
}
+1 -1
View File
@@ -1,6 +1,6 @@
struct ControllerPort {
Node::Port port;
unique_pointer<Controller> device;
std::unique_ptr<Controller> device;
//port.cpp
ControllerPort(string name);
+9 -2
View File
@@ -19,6 +19,12 @@ auto CPU::unload() -> void {
}
auto CPU::main() -> void {
if(io.resetPending) {
debugger.interrupt("Reset");
reset();
io.resetPending = 0;
}
debugger.instruction();
instruction();
}
@@ -31,10 +37,11 @@ auto CPU::step(u32 clocks) -> void {
auto CPU::power(bool reset) -> void {
MOS6502::BCD = 1;
MOS6502::power();
Thread::create(system.frequency() / 3, {&CPU::main, this});
if(!reset) MOS6502::power();
Thread::create(system.frequency() / 3, std::bind_front(&CPU::main, this));
io = {};
io.resetPending = 1;
}
}
+3
View File
@@ -5,9 +5,11 @@ struct CPU : MOS6502, Thread {
//debugger.cpp
auto load(Node::Object) -> void;
auto instruction() -> void;
auto interrupt(string_view) -> void;
struct Tracer {
Node::Debugger::Tracer::Instruction instruction;
Node::Debugger::Tracer::Notification interrupt;
} tracer;
} debugger;
@@ -39,6 +41,7 @@ struct CPU : MOS6502, Thread {
//protected:
struct IO {
n1 resetPending = 0;
n1 rdyLine = 1;
n32 scanlineCycles = 0;
n8 openBus = 0;
+5 -1
View File
@@ -9,4 +9,8 @@ auto CPU::Debugger::instruction() -> void {
}
}
auto CPU::Debugger::interrupt(string_view type) -> void {
if(tracer.interrupt->enabled()) {
tracer.interrupt->notify(type);
}
}
+1
View File
@@ -1,6 +1,7 @@
auto CPU::serialize(serializer& s) -> void {
MOS6502::serialize(s);
Thread::serialize(s);
s(io.resetPending);
s(io.rdyLine);
s(io.openBus);
}
+62 -43
View File
@@ -7,14 +7,24 @@ auto RIOT::writeRam(n8 address, n8 data) -> void {
}
auto RIOT::readIo(n8 address) -> n8 {
switch(address.bit(0, 2)) {
address &= 0x1f;
switch(address) {
case 0x00: return readPortA();
case 0x01: return port[0].direction;
case 0x02: return readPortB();
case 0x03: return port[1].direction;
case 0x04: timer.interruptFlag = address.bit(3); return timer.counter;
case 0x04: case 0x06: {
n8 data = timer.counter;
if(timer.interruptFlag && !timer.justWrapped) {
timer.interruptFlag = 0;
}
return data;
}
case 0x05: case 0x07: {
n8 output = 0;
n8 output;
output.bit(6) = 0; //TODO: PA7 IRQ Flag
output.bit(7) = timer.interruptFlag;
return output;
@@ -26,31 +36,38 @@ auto RIOT::readIo(n8 address) -> n8 {
}
auto RIOT::writeIo(n8 address, n8 data) -> void {
address &= 0x1f;
switch(address) {
case 0x00: writePortA(data); return;
case 0x01: port[0].direction = data; return;
case 0x02: writePortB(data); return;
case 0x03: port[1].direction = data; return;
case 0x14: case 0x15: case 0x16: case 0x17:
case 0x1c: case 0x1d: case 0x1e: case 0x1f: {
const n16 intervals[] = {1, 8, 64, 1024};
timer.counter = data;
timer.interval = intervals[address.bit(0, 1)];
timer.reload = timer.interval;
timer.interruptFlag = 0;
timer.interruptEnable = address.bit(3);
return; }
case 0x14: reloadTimer(data, 1, 0); return;
case 0x15: reloadTimer(data, 8, 0); return;
case 0x16: reloadTimer(data, 64, 0); return;
case 0x17: reloadTimer(data, 1024, 0); return;
case 0x1c: reloadTimer(data, 1, 1); return;
case 0x1d: reloadTimer(data, 8, 1); return;
case 0x1e: reloadTimer(data, 64, 1); return;
case 0x1f: reloadTimer(data, 1024, 1); return;
}
debug(unimplemented, "[RIOT] IO write ",hex(address), " = ", hex(data));
debug(unimplemented, "[RIOT] IO write ", hex(address), " = ", hex(data));
}
auto RIOT::readPortA() -> n8 {
n8 data;
// TODO: Handle when configured as outputs
data.bit(0, 3) = controllerPort2.read().bit(0, 4);
data.bit(4, 7) = controllerPort1.read().bit(0, 4);
return data;
n8 output = 0xff;
n8 input;
input.bit(0, 3) = controllerPort2.read().bit(0, 4);
input.bit(4, 7) = controllerPort1.read().bit(0, 4);
for(auto n : range(8)) {
output.bit(n) = port[0].direction.bit(n)? port[0].data.bit(n) : input.bit(n);
}
return output;
}
auto RIOT::writePortA(n8 data) -> void {
@@ -58,39 +75,41 @@ auto RIOT::writePortA(n8 data) -> void {
}
auto RIOT::readPortB() -> n8 {
system.controls.poll();
system.controls.poll();
n8 data;
n8 data = 0xff;
for(auto n : range(8)) if(port[1].direction.bit(n)) { data.bit(n) = port[1].data.bit(n); }
for(auto n : range(8)) {
if(port[1].direction.bit(n)) data.bit(n) = port[1].data.bit(n);
}
// Atari hard-wires these bits as input
data.bit(0) = !system.controls.reset->value();
data.bit(1) = !system.controls.select->value();
// Atari hard-wires these bits as input
data.bit(0) = !system.controls.reset->value();
data.bit(1) = !system.controls.select->value();
// These are toggle switches; flip the values on the rising edge
if(system.controls.tvType->value() && !tvTypeLatch) {
tvType = !tvType;
}
tvTypeLatch = system.controls.tvType->value();
// These are toggle switches; flip the values on the rising edge
if(system.controls.tvType->value() && !tvTypeLatch) {
tvType = !tvType;
}
tvTypeLatch = system.controls.tvType->value();
if(system.controls.leftDifficulty->value() && !leftDifficultyLatch) {
leftDifficulty = !leftDifficulty;
}
leftDifficultyLatch = system.controls.leftDifficulty->value();
if(system.controls.leftDifficulty->value() && !leftDifficultyLatch) {
leftDifficulty = !leftDifficulty;
}
leftDifficultyLatch = system.controls.leftDifficulty->value();
if(system.controls.rightDifficulty->value() && !rightDifficultyLatch) {
rightDifficulty = !rightDifficulty;
}
rightDifficultyLatch = system.controls.rightDifficulty->value();
if(system.controls.rightDifficulty->value() && !rightDifficultyLatch) {
rightDifficulty = !rightDifficulty;
}
rightDifficultyLatch = system.controls.rightDifficulty->value();
data.bit(3) = tvType;
data.bit(6) = leftDifficulty;
data.bit(7) = rightDifficulty;
data.bit(3) = tvType;
data.bit(6) = leftDifficulty;
data.bit(7) = rightDifficulty;
return data;
return data;
}
auto RIOT::writePortB(n8 data) -> void {
port[1].data = data;
}
port[1].data = data;
}
+50 -6
View File
@@ -9,7 +9,6 @@ RIOT riot;
auto RIOT::load(Node::Object parent) -> void {
node = parent->append<Node::Object>("RIOT");
ram.allocate(128);
}
@@ -18,13 +17,52 @@ auto RIOT::unload() -> void {
node.reset();
}
auto RIOT::main() -> void {
if(--timer.counter == 0xff) {
auto RIOT::reloadTimer(n8 data, n16 interval, n1 interruptEnable) -> void {
timer.counter = data;
timer.interval = interval;
timer.prescaler = interval;
timer.interruptEnable = interruptEnable;
timer.interruptFlag = 0;
timer.underflow = 0;
timer.holdZero = 0;
timer.justWrapped = 0;
}
auto RIOT::clockTimer() -> void {
timer.justWrapped = 0;
if(timer.prescaler == 0) timer.prescaler = 1;
if(--timer.prescaler) return;
timer.prescaler = timer.interval;
if(timer.holdZero) {
timer.holdZero = 0;
timer.underflow = 1;
timer.counter = 0xff;
timer.interval = 1;
timer.prescaler = 1;
timer.interruptFlag = 1;
timer.justWrapped = 1;
return;
}
step(timer.interval);
if(timer.counter == 0x00) {
timer.holdZero = 1;
return;
}
timer.counter--;
if(timer.underflow) {
timer.interval = 1;
timer.prescaler = 1;
}
}
auto RIOT::main() -> void {
clockTimer();
step(1);
}
auto RIOT::step(u32 clocks) -> void {
@@ -33,15 +71,21 @@ auto RIOT::step(u32 clocks) -> void {
}
auto RIOT::power(bool reset) -> void {
Thread::create(system.frequency() / 3, {&RIOT::main, this});
Thread::create(system.frequency() / 3, std::bind_front(&RIOT::main, this));
timer = {};
timer.interval = 1;
timer.prescaler = 1;
timer.counter = 0x00;
port[0] = {};
port[0].data = 0xff;
port[1] = {};
port[1].data = 0xff;
leftDifficulty = 1;
leftDifficultyLatch = 0;
rightDifficulty = 1;
rightDifficultyLatch = 0;
tvType = 1;
tvTypeLatch = 0;
}
}
+9 -5
View File
@@ -10,7 +10,8 @@ struct RIOT : Thread {
auto step(u32 clocks) -> void;
auto power(bool reset) -> void;
auto decrementTimer() -> void;
auto clockTimer() -> void;
auto reloadTimer(n8 data, n16 interval, n1 interruptEnable) -> void;
//io.cpp
auto readRam(n8 address) -> n8;
@@ -27,11 +28,14 @@ struct RIOT : Thread {
auto serialize(serializer&) -> void;
struct {
u8 counter;
n8 counter;
n16 interval;
n16 reload;
n1 interruptEnable;
n1 interruptFlag;
n16 prescaler;
n1 interruptEnable;
n1 interruptFlag;
n1 underflow;
n1 holdZero;
n1 justWrapped;
} timer;
struct Port {
+5 -2
View File
@@ -1,13 +1,16 @@
//serialization.cpp
auto RIOT::serialize(serializer& s) -> void {
Thread::serialize(s);
s(ram);
s(timer.counter);
s(timer.interval);
s(timer.reload);
s(timer.prescaler);
s(timer.interruptEnable);
s(timer.interruptFlag);
s(timer.underflow);
s(timer.holdZero);
s(timer.justWrapped);
for(auto n : range(2)) {
s(port[n].data);
+1 -1
View File
@@ -1,4 +1,4 @@
static const string SerializerVersion = "v139";
static const string SerializerVersion = "v140";
auto System::serialize(bool synchronize) -> serializer {
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
+13 -10
View File
@@ -1,8 +1,9 @@
#include <a26/a26.hpp>
#include <algorithm>
namespace ares::Atari2600 {
auto enumerate() -> vector<string> {
auto enumerate() -> std::vector<string> {
return {
"[Atari] Atari 2600 (NTSC)",
"[Atari] Atari 2600 (PAL)",
@@ -11,7 +12,8 @@ auto enumerate() -> vector<string> {
}
auto load(Node::System& node, string name) -> bool {
if(!enumerate().find(name)) return false;
auto list = enumerate();
if(std::find(list.begin(), list.end(), name) == list.end()) return false;
return system.load(node, name);
}
@@ -53,14 +55,15 @@ auto System::load(Node::System& root, string name) -> bool {
information.frequency = 3546894;
}
node = Node::System::create(information.name);
node->setGame({&System::game, this});
node->setRun({&System::run, this});
node->setPower({&System::power, this});
node->setSave({&System::save, this});
node->setUnload({&System::unload, this});
node->setSerialize({&System::serialize, this});
node->setUnserialize({&System::unserialize, this});
node = std::make_shared<Core::System>(information.name);
node->setAttribute("configuration", name);
node->setGame(std::bind_front(&System::game, this));
node->setRun(std::bind_front(&System::run, this));
node->setPower(std::bind_front(&System::power, this));
node->setSave(std::bind_front(&System::save, this));
node->setUnload(std::bind_front(&System::unload, this));
node->setSerialize([this](bool s){ return this->serialize(s); });
node->setUnserialize([this](serializer& s){ return this->unserialize(s); });
root = node;
scheduler.reset();
+2 -2
View File
@@ -18,7 +18,7 @@ auto TIA::load(Node::Object parent) -> void {
node = parent->append<Node::Object>("TIA");
screen = node->append<Node::Video::Screen>("Screen", 180, displayHeight());
screen->colors(1 << 7, {&TIA::color, this});
screen->colors(1 << 7, std::bind_front(&TIA::color, this));
screen->setSize(180, displayHeight());
screen->setScale(2.0, 1.0);
Region::PAL() ? screen->setAspect(38.0, 45.0) : screen->setAspect(4.0, 5.0);
@@ -123,7 +123,7 @@ auto TIA::step(u32 clocks) -> void {
}
auto TIA::power(bool reset) -> void {
Thread::create(system.frequency(), {&TIA::main, this});
Thread::create(system.frequency(), std::bind_front(&TIA::main, this));
screen->power();
io = {};
playfield = {};
+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 = "142";
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)
}
+21 -6
View File
@@ -3,6 +3,10 @@
#include <libco/libco.h>
#include <sljit.h>
#include <vector>
#include <ranges>
#include <algorithm>
#include <nall/platform.hpp>
#include <nall/adaptive-array.hpp>
#include <nall/any.hpp>
@@ -22,14 +26,13 @@
#include <nall/random.hpp>
#include <nall/serializer.hpp>
#include <nall/set.hpp>
#include <nall/shared-pointer.hpp>
#include <nall/span-helpers.hpp>
#include <nall/string.hpp>
#include <nall/terminal.hpp>
#include <nall/thread.hpp>
#include <nall/traits.hpp>
#include <nall/unique-pointer.hpp>
#include <memory>
#include <nall/variant.hpp>
#include <nall/vector.hpp>
#include <nall/vfs.hpp>
#include <nall/cd.hpp>
#include <nall/dsp/iir/one-pole.hpp>
@@ -51,8 +54,8 @@ namespace ares {
extern const u32 SerializerSignature;
namespace VFS {
using Pak = shared_pointer<vfs::directory>;
using File = shared_pointer<vfs::file>;
using Pak = std::shared_ptr<vfs::directory>;
using File = std::shared_ptr<vfs::file>;
}
namespace Video {
@@ -66,11 +69,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>
+12 -12
View File
@@ -4,40 +4,40 @@ Debug _debug;
auto Debug::reset() -> void {
_totalNotices = 0;
_unhandledNotices.reset();
_unimplementedNotices.reset();
_unusualNotices.reset();
_unverifiedNotices.reset();
_unhandledNotices.clear();
_unimplementedNotices.clear();
_unusualNotices.clear();
_unverifiedNotices.clear();
}
auto Debug::_unhandled(const string& text) -> void {
if(_unhandledNotices.find(text)) return;
if(std::ranges::find(_unhandledNotices, text) != _unhandledNotices.end()) return;
if(_totalNotices++ > 256) return;
_unhandledNotices.append(text);
_unhandledNotices.push_back(text);
print(terminal::color::yellow("[unhandled] "), text, "\n");
}
auto Debug::_unimplemented(const string& text) -> void {
if(_unimplementedNotices.find(text)) return;
if(std::ranges::find(_unimplementedNotices, text) != _unimplementedNotices.end()) return;
if(_totalNotices++ > 256) return;
_unimplementedNotices.append(text);
_unimplementedNotices.push_back(text);
print(terminal::color::magenta("[unimplemented] "), text, "\n");
}
auto Debug::_unusual(const string& text) -> void {
if(_unusualNotices.find(text)) return;
if(std::ranges::find(_unusualNotices, text) != _unusualNotices.end()) return;
if(_totalNotices++ > 256) return;
_unusualNotices.append(text);
_unusualNotices.push_back(text);
print(terminal::color::cyan("[unusual] "), text, "\n");
}
auto Debug::_unverified(const string& text) -> void {
if(_unverifiedNotices.find(text)) return;
if(std::ranges::find(_unverifiedNotices, text) != _unverifiedNotices.end()) return;
if(_totalNotices++ > 256) return;
_unverifiedNotices.append(text);
_unverifiedNotices.push_back(text);
print(terminal::color::gray("[unverified] "), text, "\n");
}
+4 -4
View File
@@ -26,10 +26,10 @@ private:
auto _unverified(const string&) -> void;
u64 _totalNotices = 0;
vector<string> _unhandledNotices;
vector<string> _unimplementedNotices;
vector<string> _unusualNotices;
vector<string> _unverifiedNotices;
std::vector<string> _unhandledNotices;
std::vector<string> _unimplementedNotices;
std::vector<string> _unusualNotices;
std::vector<string> _unverifiedNotices;
};
extern Debug _debug;
+3 -2
View File
@@ -1,6 +1,7 @@
#pragma once
#include <ares/memory/memory.hpp>
#include <span>
namespace ares::Memory {
@@ -32,7 +33,7 @@ struct Readable {
auto load(VFS::File fp) -> void {
if(!self.size) allocate(fp->size());
fp->read({self.data, min(fp->size(), self.size * sizeof(T))});
fp->read({(u8*)self.data, min(fp->size(), self.size * sizeof(T))});
for(u32 address = self.size; address <= self.mask; address++) {
self.data[address] = self.data[mirror(address, self.size)];
}
@@ -59,7 +60,7 @@ struct Readable {
auto end() const -> const T* { return &self.data[self.size]; }
auto serialize(serializer& s) -> void {
s(array_span<T>{self.data, self.size});
s(std::span<T>{self.data, self.size});
}
//private:
+4 -3
View File
@@ -1,6 +1,7 @@
#pragma once
#include <ares/memory/memory.hpp>
#include <span>
namespace ares::Memory {
@@ -32,14 +33,14 @@ struct Writable {
auto load(VFS::File fp) -> void {
if(!self.size) allocate(fp->size());
fp->read({self.data, min(fp->size(), self.size * sizeof(T))});
fp->read({(u8*)self.data, min(fp->size(), self.size * sizeof(T))});
for(u32 address = self.size; address <= self.mask; address++) {
self.data[address] = self.data[mirror(address, self.size)];
}
}
auto save(VFS::File fp) -> void {
fp->write({self.data, min(fp->size(), self.size * sizeof(T))});
fp->write({(const u8*)self.data, min(fp->size(), self.size * sizeof(T))});
}
explicit operator bool() const { return (bool)self.data; }
@@ -61,7 +62,7 @@ struct Writable {
auto end() const -> const T* { return &self.data[self.size]; }
auto serialize(serializer& s) -> void {
s(array_span<T>{self.data, self.size});
s(std::span<T>{self.data, self.size});
}
private:
+12 -12
View File
@@ -1,5 +1,5 @@
auto Stream::setChannels(u32 channels) -> void {
_channels.reset();
_channels.clear();
_channels.resize(channels);
}
@@ -12,7 +12,7 @@ auto Stream::setResamplerFrequency(f64 resamplerFrequency) -> void {
_resamplerFrequency = resamplerFrequency;
for(auto& channel : _channels) {
channel.nyquist.reset();
channel.nyquist.clear();
channel.resampler.reset(_frequency, _resamplerFrequency);
}
@@ -25,7 +25,7 @@ auto Stream::setResamplerFrequency(f64 resamplerFrequency) -> void {
DSP::IIR::Biquad filter;
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
filter.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, _frequency, q);
channel.nyquist.append(filter);
channel.nyquist.push_back(filter);
}
}
}
@@ -37,7 +37,7 @@ auto Stream::setMuted(bool muted) -> void {
auto Stream::resetFilters() -> void {
for(auto& channel : _channels) {
channel.filters.reset();
channel.filters.clear();
}
}
@@ -47,13 +47,13 @@ auto Stream::addLowPassFilter(f64 cutoffFrequency, u32 order, u32 passes) -> voi
if(order == 1) {
Filter filter{Filter::Mode::OnePole, Filter::Type::LowPass, Filter::Order::First};
filter.onePole.reset(DSP::IIR::OnePole::Type::LowPass, cutoffFrequency, _frequency);
channel.filters.append(filter);
channel.filters.push_back(filter);
}
if(order == 2) {
Filter filter{Filter::Mode::Biquad, Filter::Type::LowPass, Filter::Order::Second};
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
filter.biquad.reset(DSP::IIR::Biquad::Type::LowPass, cutoffFrequency, _frequency, q);
channel.filters.append(filter);
channel.filters.push_back(filter);
}
}
}
@@ -65,13 +65,13 @@ auto Stream::addHighPassFilter(f64 cutoffFrequency, u32 order, u32 passes) -> vo
if(order == 1) {
Filter filter{Filter::Mode::OnePole, Filter::Type::HighPass, Filter::Order::First};
filter.onePole.reset(DSP::IIR::OnePole::Type::HighPass, cutoffFrequency, _frequency);
channel.filters.append(filter);
channel.filters.push_back(filter);
}
if(order == 2) {
Filter filter{Filter::Mode::Biquad, Filter::Type::HighPass, Filter::Order::Second};
f64 q = DSP::IIR::Biquad::butterworth(passes * 2, pass);
filter.biquad.reset(DSP::IIR::Biquad::Type::HighPass, cutoffFrequency, _frequency, q);
channel.filters.append(filter);
channel.filters.push_back(filter);
}
}
}
@@ -83,7 +83,7 @@ auto Stream::addLowShelfFilter(f64 cutoffFrequency, u32 order, f64 gain, f64 slo
Filter filter{Filter::Mode::Biquad, Filter::Type::LowShelf, Filter::Order::Second};
f64 q = DSP::IIR::Biquad::shelf(gain, slope);
filter.biquad.reset(DSP::IIR::Biquad::Type::LowShelf, cutoffFrequency, _frequency, q);
channel.filters.append(filter);
channel.filters.push_back(filter);
}
}
}
@@ -94,13 +94,13 @@ auto Stream::addHighShelfFilter(f64 cutoffFrequency, u32 order, f64 gain, f64 sl
Filter filter{Filter::Mode::Biquad, Filter::Type::HighShelf, Filter::Order::Second};
f64 q = DSP::IIR::Biquad::shelf(gain, slope);
filter.biquad.reset(DSP::IIR::Biquad::Type::HighShelf, cutoffFrequency, _frequency, q);
channel.filters.append(filter);
channel.filters.push_back(filter);
}
}
}
auto Stream::pending() const -> bool {
return _channels && _channels[0].resampler.pending();
return !_channels.empty() && _channels[0].resampler.pending();
}
auto Stream::read(f64 samples[]) -> u32 {
@@ -127,5 +127,5 @@ auto Stream::write(const f64 samples[]) -> void {
//if there are samples pending, then alert the frontend to possibly process them.
//this will generally happen when every audio stream has pending samples to be mixed.
if(pending()) platform->audio(shared());
if(pending()) platform->audio(std::static_pointer_cast<Core::Audio::Stream>(shared_from_this()));
}
+3 -3
View File
@@ -38,11 +38,11 @@ protected:
DSP::IIR::Biquad biquad;
};
struct Channel {
vector<Filter> filters;
vector<DSP::IIR::Biquad> nyquist;
std::vector<Filter> filters;
std::vector<DSP::IIR::Biquad> nyquist;
DSP::Resampler::Cubic resampler;
};
vector<Channel> _channels;
std::vector<Channel> _channels;
f64 _frequency = 48000.0;
f64 _resamplerFrequency = 48000.0;
bool _muted = false;
+10 -8
View File
@@ -4,26 +4,28 @@
struct Class {
struct Instance {
const string identifier;
const function<Node::Object ()> create;
const std::function<Node::Object ()> create;
};
static auto classes() -> vector<Instance>& {
static vector<Instance> classes;
static auto classes() -> std::vector<Instance>& {
static std::vector<Instance> classes;
return classes;
}
template<typename T> static auto register() -> void {
if(!classes().find([&](auto instance) { return instance.identifier == T::identifier(); })) {
classes().append({T::identifier(), &T::create});
auto& cls = classes();
auto it = std::ranges::find_if(cls, [&](const Instance& instance) { return instance.identifier == T::identifier(); });
if(it == cls.end()) {
cls.push_back({T::identifier(), &T::create});
} else {
throw;
}
}
static auto create(string identifier) -> Node::Object {
if(auto index = classes().find([&](auto instance) { return instance.identifier == identifier; })) {
return classes()[*index].create();
}
auto& cls = classes();
auto it = std::ranges::find_if(cls, [&](const Instance& instance) { return instance.identifier == identifier; });
if(it != cls.end()) return it->create();
if(identifier == "Object") throw; //should never occur: detects unregistered classes
return create("Object");
}
+2 -2
View File
@@ -5,7 +5,7 @@ struct RealTimeClock : Component {
auto update() -> void { if(_update) return _update(); }
auto timestamp() const -> u64 { return _timestamp; }
auto setUpdate(function<void ()> update) -> void { _update = update; }
auto setUpdate(std::function<void ()> update) -> void { _update = update; }
auto setTimestamp(u64 timestamp) -> void { _timestamp = timestamp; }
auto synchronize(u64 timestamp = 0) -> void {
@@ -25,6 +25,6 @@ struct RealTimeClock : Component {
}
protected:
function<void ()> _update;
std::function<void ()> _update;
u64 _timestamp;
};
+3 -3
View File
@@ -6,10 +6,10 @@ struct Graphics : Debugger {
auto width() const -> u32 { return _width; }
auto height() const -> u32 { return _height; }
auto capture() const -> vector<u32> { if(_capture) return _capture(); return {}; }
auto capture() const -> std::vector<u32> { if(_capture) return _capture(); return {}; }
auto setSize(u32 width, u32 height) -> void { _width = width, _height = height; }
auto setCapture(function<vector<u32> ()> capture) -> void { _capture = capture; }
auto setCapture(std::function<std::vector<u32> ()> capture) -> void { _capture = capture; }
auto serialize(string& output, string depth) -> void override {
Debugger::serialize(output, depth);
@@ -22,5 +22,5 @@ struct Graphics : Debugger {
protected:
u32 _width = 0;
u32 _height = 0;
function<vector<u32> ()> _capture;
std::function<std::vector<u32> ()> _capture;
};
+4 -4
View File
@@ -9,8 +9,8 @@ struct Memory : Debugger {
auto write(u32 address, u8 data) const -> void { if(_write) return _write(address, data); }
auto setSize(u32 size) -> void { _size = size; }
auto setRead(function<u8 (u32)> read) -> void { _read = read; }
auto setWrite(function<void (u32, u8)> write) -> void { _write = write; }
auto setRead(std::function<u8 (u32)> read) -> void { _read = read; }
auto setWrite(std::function<void (u32, u8)> write) -> void { _write = write; }
auto serialize(string& output, string depth) -> void override {
Debugger::serialize(output, depth);
@@ -22,6 +22,6 @@ struct Memory : Debugger {
protected:
u32 _size = 0;
function<u8 (u32)> _read;
function<void (u32, u8)> _write;
std::function<u8 (u32)> _read;
std::function<void (u32, u8)> _write;
};
+2 -2
View File
@@ -6,7 +6,7 @@ struct Properties : Debugger {
auto query() const -> string { if(_query) return _query(); return {}; }
auto setQuery(function<string ()> query) -> void { _query = query; }
auto setQuery(std::function<string ()> query) -> void { _query = query; }
auto serialize(string& output, string depth) -> void override {
Debugger::serialize(output, depth);
@@ -17,5 +17,5 @@ struct Properties : Debugger {
}
protected:
function<string ()> _query;
std::function<string ()> _query;
};
+15 -5
View File
@@ -23,11 +23,20 @@ struct Instruction : Tracer {
auto setDepth(u32 depth) -> void {
_depth = depth;
_history.reset();
_history.clear();
_history.resize(depth);
for(auto& history : _history) history = ~0ull;
}
auto setEnabled(bool enabled) -> void {
Tracer::setTerminal(enabled);
if(!enabled) {
_omitted = 0;
setMask(_mask);
setDepth(_depth);
}
}
auto address(u64 address) -> bool {
address &= ~0ull >> (64 - _addressBits); //mask upper bits of address
_address = address;
@@ -49,7 +58,7 @@ struct Instruction : Tracer {
for(auto index : range(_depth - 1)) {
_history[index] = _history[index + 1];
}
_history.last() = _address;
_history.back() = _address;
}
return true;
@@ -71,7 +80,8 @@ struct Instruction : Tracer {
if(!enabled()) return;
if(_omitted) {
PlatformLog(shared(), {"[Omitted: ", _omitted, "]"});
auto message = string{ "[Omitted: ", _omitted, "]" };
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), message);
_omitted = 0;
}
@@ -82,7 +92,7 @@ struct Instruction : Tracer {
context, " ",
extra
};
PlatformLog(shared(), {output.strip()});
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), {output.strip()});
}
auto serialize(string& output, string depth) -> void override {
@@ -135,6 +145,6 @@ protected:
//unserialized:
n64 _address = 0;
n64 _omitted = 0;
vector<u64> _history;
std::vector<u64> _history;
hashset<VisitMask> _masks;
};
@@ -6,7 +6,7 @@ struct Notification : Tracer {
auto notify(const string& message = {}) -> void {
if(!enabled()) return;
PlatformLog(shared(), message);
PlatformLog(std::dynamic_pointer_cast<Tracer>(shared_from_this()), message);
}
protected:
+2 -2
View File
@@ -12,7 +12,7 @@ struct Tracer : Debugger {
auto file() const -> bool { return _file; }
auto autoLineBreak() const -> bool { return _autoLineBreak; }
auto setToggle(function<void ()> toggle) -> void { _toggle = toggle; }
auto setToggle(std::function<void ()> toggle) -> void { _toggle = toggle; }
auto setComponent(string component) -> void { _component = component; }
auto setPrefix(bool prefix) -> void { _prefix = prefix; }
auto setTerminal(bool terminal) -> void { _terminal = terminal; if(_toggle) _toggle(); }
@@ -36,7 +36,7 @@ struct Tracer : Debugger {
}
protected:
function<void ()> _toggle;
std::function<void ()> _toggle;
string _component;
bool _prefix = false;
bool _terminal = false;
+51
View File
@@ -5,6 +5,57 @@ struct Axis : Input {
auto value() const -> s64 { return _value; }
auto setValue(s64 value) -> void { _value = value; }
auto setOperatingRange(s16 position, double saturationRadius, double offset) -> double {
return position * saturationRadius / 32767.0 + offset;
}
auto processDeadzoneAndResponseCurve(double position, double innerDeadzone, double cardinalMax, double offset) -> double {
auto lengthAbsolute = abs(position - offset);
if(lengthAbsolute <= innerDeadzone) {
position = offset;
} else {
lengthAbsolute = (lengthAbsolute - innerDeadzone) * (cardinalMax) / (cardinalMax - innerDeadzone) / lengthAbsolute;
position = (position - offset) * lengthAbsolute + offset;
}
return position;
}
auto revisePosition(double position, double length, double saturationRadius, double offset) -> double {
if(length > saturationRadius) {
length = saturationRadius / length;
position = (position - offset) * length + offset;
}
return position;
}
auto applyGateBoundaries(double innerDeadzone, double cardinalMax, double diagonalMax, double positionX, double positionY, double offset, double& boundedPositionX, double& boundedPositionY) -> void {
if(positionX != offset && positionY != offset) {
auto slope = (positionY - offset) / (positionX - offset);
auto edgex = copysign(cardinalMax / (abs(slope) + (cardinalMax - diagonalMax) / diagonalMax), positionX);
auto edgey = copysign(min(abs(edgex * slope), cardinalMax / (1.0 / abs(slope) + (cardinalMax - diagonalMax) / diagonalMax)), positionY);
edgex = edgey / slope;
auto distanceToEdge = hypot(edgex, edgey);
auto length = hypot(positionX - offset, positionY - offset);
if(length > distanceToEdge) {
positionX = edgex + offset;
positionY = edgey + offset;
}
}
boundedPositionX = positionX;
boundedPositionY = positionY;
}
auto clampAxisToNearestBoundary(double position, double offset, double cardinalMax) -> double {
if(abs(position - offset) > cardinalMax) position = copysign(cardinalMax, position - offset) + offset;
return position;
}
auto counteractPrecisionError(double position) -> double {
return copysign(abs(position) + 1e-09, position);
}
protected:
s64 _value = 0;
s64 _minimum = -32768;
+38 -34
View File
@@ -3,6 +3,7 @@ namespace ares::Core {
struct System;
struct Peripheral;
struct Port;
struct Tape;
namespace Component {
struct Component;
struct RealTimeClock;
@@ -45,47 +46,48 @@ namespace ares::Core {
}
namespace ares::Node {
using Object = shared_pointer<Core::Object>;
using System = shared_pointer<Core::System>;
using Peripheral = shared_pointer<Core::Peripheral>;
using Port = shared_pointer<Core::Port>;
using Object = std::shared_ptr<Core::Object>;
using System = std::shared_ptr<Core::System>;
using Peripheral = std::shared_ptr<Core::Peripheral>;
using Port = std::shared_ptr<Core::Port>;
using Tape = std::shared_ptr<Core::Tape>;
namespace Component {
using Component = shared_pointer<Core::Component::Component>;
using RealTimeClock = shared_pointer<Core::Component::RealTimeClock>;
using Component = std::shared_ptr<Core::Component::Component>;
using RealTimeClock = std::shared_ptr<Core::Component::RealTimeClock>;
}
namespace Video {
using Video = shared_pointer<Core::Video::Video>;
using Sprite = shared_pointer<Core::Video::Sprite>;
using Screen = shared_pointer<Core::Video::Screen>;
using Video = std::shared_ptr<Core::Video::Video>;
using Sprite = std::shared_ptr<Core::Video::Sprite>;
using Screen = std::shared_ptr<Core::Video::Screen>;
}
namespace Audio {
using Audio = shared_pointer<Core::Audio::Audio>;
using Stream = shared_pointer<Core::Audio::Stream>;
using Audio = std::shared_ptr<Core::Audio::Audio>;
using Stream = std::shared_ptr<Core::Audio::Stream>;
}
namespace Input {
using Input = shared_pointer<Core::Input::Input>;
using Button = shared_pointer<Core::Input::Button>;
using Axis = shared_pointer<Core::Input::Axis>;
using Trigger = shared_pointer<Core::Input::Trigger>;
using Rumble = shared_pointer<Core::Input::Rumble>;
using Input = std::shared_ptr<Core::Input::Input>;
using Button = std::shared_ptr<Core::Input::Button>;
using Axis = std::shared_ptr<Core::Input::Axis>;
using Trigger = std::shared_ptr<Core::Input::Trigger>;
using Rumble = std::shared_ptr<Core::Input::Rumble>;
}
namespace Setting {
using Setting = shared_pointer<Core::Setting::Setting>;
using Boolean = shared_pointer<Core::Setting::Boolean>;
using Natural = shared_pointer<Core::Setting::Natural>;
using Integer = shared_pointer<Core::Setting::Integer>;
using Real = shared_pointer<Core::Setting::Real>;
using String = shared_pointer<Core::Setting::String>;
using Setting = std::shared_ptr<Core::Setting::Setting>;
using Boolean = std::shared_ptr<Core::Setting::Boolean>;
using Natural = std::shared_ptr<Core::Setting::Natural>;
using Integer = std::shared_ptr<Core::Setting::Integer>;
using Real = std::shared_ptr<Core::Setting::Real>;
using String = std::shared_ptr<Core::Setting::String>;
}
namespace Debugger {
using Debugger = shared_pointer<Core::Debugger::Debugger>;
using Memory = shared_pointer<Core::Debugger::Memory>;
using Graphics = shared_pointer<Core::Debugger::Graphics>;
using Properties = shared_pointer<Core::Debugger::Properties>;
using Debugger = std::shared_ptr<Core::Debugger::Debugger>;
using Memory = std::shared_ptr<Core::Debugger::Memory>;
using Graphics = std::shared_ptr<Core::Debugger::Graphics>;
using Properties = std::shared_ptr<Core::Debugger::Properties>;
namespace Tracer {
using Tracer = shared_pointer<Core::Debugger::Tracer::Tracer>;
using Notification = shared_pointer<Core::Debugger::Tracer::Notification>;
using Instruction = shared_pointer<Core::Debugger::Tracer::Instruction>;
using Tracer = std::shared_ptr<Core::Debugger::Tracer::Tracer>;
using Notification = std::shared_ptr<Core::Debugger::Tracer::Notification>;
using Instruction = std::shared_ptr<Core::Debugger::Tracer::Instruction>;
}
}
}
@@ -102,6 +104,7 @@ namespace ares::Core {
#include <ares/node/system.hpp>
#include <ares/node/peripheral.hpp>
#include <ares/node/port.hpp>
#include <ares/node/tape.hpp>
namespace Component {
#include <ares/node/component/component.hpp>
#include <ares/node/component/real-time-clock.hpp>
@@ -164,9 +167,10 @@ namespace ares::Node {
}
static inline auto parent(Object child) -> Object {
if(!child || !child->parent()) return {};
if(auto parent = child->parent().acquire()) return parent;
return {};
if(!child) return {};
auto wp = child->parent();
if(wp.expired()) return {};
return wp.lock();
}
template<typename T>
@@ -177,8 +181,8 @@ namespace ares::Node {
}
template<typename T>
static inline auto enumerate(Object from) -> vector<T> {
vector<T> objects;
static inline auto enumerate(Object from) -> std::vector<T> {
std::vector<T> objects;
if(from) from->enumerate<T>(objects);
return objects;
}
+45 -38
View File
@@ -3,13 +3,13 @@
#define DeclareClass(Type, Name) \
static auto identifier() -> string { return Name; } \
static auto create() -> Node::Object { return new Type; } \
static auto create() -> Node::Object { return std::make_shared<Type>(); } \
auto identity() const -> string override { return Name; } \
private: static inline Class::Register<Type> register; public: \
struct Object : shared_pointer_this<Object> {
struct Object : std::enable_shared_from_this<Object> {
static auto identifier() -> string { return "Object"; }
static auto create() -> Node::Object { return new Object; }
static auto create() -> Node::Object { return std::make_shared<Object>(); }
virtual auto identity() const -> string { return "Object"; }
private: static inline Class::Register<Object> register; public:
//DeclareClass(Object, "object")
@@ -18,44 +18,47 @@ struct Object : shared_pointer_this<Object> {
virtual ~Object() = default;
auto name() const -> string { return _name; }
auto parent() const -> shared_pointer_weak<Object> { return _parent; }
auto parent() const -> std::weak_ptr<Object> { return _parent; }
auto setName(string_view name) -> void { _name = name; }
auto prepend(Node::Object node) -> Node::Object {
if(auto found = find(node)) return found;
_nodes.prepend(node);
node->_parent = shared();
_nodes.insert(_nodes.begin(), node);
node->_parent = shared_from_this();
PlatformAttach(node);
return node;
}
template<typename T, typename... P>
auto prepend(P&&... p) -> Node::Object {
using Type = typename T::type;
return prepend(shared_pointer<Type>::create(std::forward<P>(p)...));
auto prepend(P&&... p) -> std::shared_ptr<typename T::element_type> {
using Type = typename T::element_type;
auto node = std::make_shared<Type>(std::forward<P>(p)...);
prepend(node);
return node;
}
auto append(Node::Object node) -> Node::Object {
if(auto found = find(node)) return found;
_nodes.append(node);
node->_parent = shared();
_nodes.push_back(node);
node->_parent = shared_from_this();
PlatformAttach(node);
return node;
}
template<typename T, typename... P>
auto append(P&&... p) -> Node::Object {
using Type = typename T::type;
return append(shared_pointer<Type>::create(std::forward<P>(p)...));
auto append(P&&... p) -> std::shared_ptr<typename T::element_type> {
using Type = typename T::element_type;
auto node = std::make_shared<Type>(std::forward<P>(p)...);
append(node);
return node;
}
auto remove(Node::Object node) -> void {
if(auto index = _nodes.find(node)) {
if(std::erase(_nodes, node)) {
PlatformDetach(node);
node->reset();
node->_parent.reset();
_nodes.remove(*index);
}
}
@@ -65,13 +68,12 @@ struct Object : shared_pointer_this<Object> {
node->reset();
node->_parent.reset();
}
_nodes.reset();
_nodes.clear();
}
template<typename T>
auto cast() -> shared_pointer<typename T::type> {
if(dynamic_cast<typename T::type*>(this)) return shared();
return {};
auto cast() -> std::shared_ptr<typename T::element_type> {
return std::dynamic_pointer_cast<typename T::element_type>(shared_from_this());
}
template<typename T>
@@ -80,17 +82,20 @@ struct Object : shared_pointer_this<Object> {
}
template<typename T>
auto find() -> vector<shared_pointer<typename T::type>> {
vector<shared_pointer<typename T::type>> result;
if(dynamic_cast<typename T::type*>(this)) {
if(auto instance = shared()) result.append(instance);
auto find() -> std::vector<std::shared_ptr<typename T::element_type>> {
std::vector<std::shared_ptr<typename T::element_type>> result;
if(dynamic_cast<typename T::element_type*>(this)) {
if(auto instance = cast<T>()) result.push_back(instance);
}
for(auto& node : _nodes) {
auto sub = node->find<T>();
std::ranges::copy(sub, std::back_inserter(result));
}
for(auto& node : _nodes) result.append(node->find<T>());
return result;
}
template<typename T>
auto find(u32 index) -> shared_pointer<typename T::type> {
auto find(u32 index) -> std::shared_ptr<typename T::element_type> {
auto result = find<T>();
if(index < result.size()) return result[index];
return {};
@@ -106,31 +111,33 @@ struct Object : shared_pointer_this<Object> {
template<typename T = Node::Object>
auto find(string name) -> T {
using Type = typename T::type;
auto path = name.split("/");
name = path.takeFirst();
using Type = typename T::element_type;
auto path = nall::split(name, "/");
if(path.empty()) return {};
name = path.front();
path.erase(path.begin());
for(auto& node : _nodes) {
if(node->_name != name) continue;
if(path) return node->find<T>(path.merge("/"));
if(node->identity() == Type::identifier()) return node;
if(!path.empty()) return node->find<T>(nall::merge(path, "/"));
if(node->identity() == Type::identifier()) return node->template cast<T>();
}
return {};
}
template<typename T = Node::Object>
auto scan(string name) -> T {
using Type = typename T::type;
using Type = typename T::element_type;
for(auto& node : _nodes) {
if(node->identity() == Type::identifier() && node->_name == name) return node;
if(node->identity() == Type::identifier() && node->_name == name) return node->template cast<T>();
if(auto result = node->scan<T>(name)) return result;
}
return {};
}
template<typename T>
auto enumerate(vector<T>& objects) -> void {
using Type = typename T::type;
if(auto instance = cast<T>()) objects.append(instance);
auto enumerate(std::vector<T>& objects) -> void {
using Type = typename T::element_type;
if(auto instance = cast<T>()) objects.push_back(instance);
for(auto& node : _nodes) node->enumerate<T>(objects);
}
@@ -230,6 +237,6 @@ protected:
string _name;
VFS::Pak _pak;
set<Attribute> _attributes;
shared_pointer_weak<Object> _parent;
vector<Node::Object> _nodes;
std::weak_ptr<Object> _parent;
std::vector<Node::Object> _nodes;
};
+9 -9
View File
@@ -5,15 +5,15 @@ struct Port : Object {
auto type() const -> string { return _type; }
auto family() const -> string { return _family; }
auto hotSwappable() const -> bool { return _hotSwappable; }
auto supported() const -> vector<string> { return _supported; }
auto supported() const -> std::vector<string> { return _supported; }
auto setAllocate(function<Node::Peripheral (string)> allocate) -> void { _allocate = allocate; }
auto setConnect(function<void ()> connect) -> void { _connect = connect; }
auto setDisconnect(function<void ()> disconnect) -> void { _disconnect = disconnect; }
auto setAllocate(std::function<Node::Peripheral (string)> allocate) -> void { _allocate = allocate; }
auto setConnect(std::function<void ()> connect) -> void { _connect = connect; }
auto setDisconnect(std::function<void ()> disconnect) -> void { _disconnect = disconnect; }
auto setType(string type) -> void { _type = type; }
auto setFamily(string family) -> void { _family = family; }
auto setHotSwappable(bool hotSwappable) -> void { _hotSwappable = hotSwappable; }
auto setSupported(vector<string> supported) -> void { _supported = supported; }
auto setSupported(std::vector<string> supported) -> void { _supported = supported; }
auto connected() -> Node::Peripheral {
return find<Node::Peripheral>(0);
@@ -64,11 +64,11 @@ struct Port : Object {
}
protected:
function<Node::Peripheral (string)> _allocate;
function<void ()> _connect;
function<void ()> _disconnect;
std::function<Node::Peripheral (string)> _allocate;
std::function<void ()> _connect;
std::function<void ()> _disconnect;
string _type;
string _family;
bool _hotSwappable = false;
vector<string> _supported;
std::vector<string> _supported;
};
+4 -4
View File
@@ -1,7 +1,7 @@
struct Boolean : Setting {
DeclareClass(Boolean, "setting.boolean")
Boolean(string name = {}, bool value = {}, function<void (bool)> modify = {}) : Setting(name) {
Boolean(string name = {}, bool value = {}, std::function<void (bool)> modify = {}) : Setting(name) {
_currentValue = value;
_latchedValue = value;
_modify = modify;
@@ -11,7 +11,7 @@ struct Boolean : Setting {
auto value() const -> bool { return _currentValue; }
auto latch() const -> bool { return _latchedValue; }
auto setModify(function<void (bool)> modify) { _modify = modify; }
auto setModify(std::function<void (bool)> modify) { _modify = modify; }
auto setValue(bool value) -> void {
_currentValue = value;
@@ -26,11 +26,11 @@ struct Boolean : Setting {
auto readValue() const -> string override { return value(); }
auto readLatch() const -> string override { return latch(); }
auto readAllowedValues() const -> vector<string> override { return {"false", "true"}; }
auto readAllowedValues() const -> std::vector<string> override { return {"false", "true"}; }
auto writeValue(string value) -> void override { setValue(value.boolean()); }
protected:
function<void (bool)> _modify;
std::function<void (bool)> _modify;
bool _currentValue = {};
bool _latchedValue = {};
};
+10 -10
View File
@@ -1,7 +1,7 @@
struct Integer : Setting {
DeclareClass(Integer, "setting.integer")
Integer(string name = {}, s64 value = {}, function<void (s64)> modify = {}) : Setting(name) {
Integer(string name = {}, s64 value = {}, std::function<void (s64)> modify = {}) : Setting(name) {
_currentValue = value;
_latchedValue = value;
_modify = modify;
@@ -11,10 +11,10 @@ struct Integer : Setting {
auto value() const -> s64 { return _currentValue; }
auto latch() const -> s64 { return _latchedValue; }
auto setModify(function<void (s64)> modify) { _modify = modify; }
auto setModify(std::function<void (s64)> modify) { _modify = modify; }
auto setValue(s64 value) -> void {
if(_allowedValues && !_allowedValues.find(value)) return;
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
_currentValue = value;
if(_dynamic) setLatch();
}
@@ -25,23 +25,23 @@ struct Integer : Setting {
modify(_latchedValue);
}
auto setAllowedValues(vector<s64> allowedValues) -> void {
auto setAllowedValues(std::vector<s64> allowedValues) -> void {
_allowedValues = allowedValues;
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
}
auto readValue() const -> string override { return value(); }
auto readLatch() const -> string override { return latch(); }
auto readAllowedValues() const -> vector<string> override {
vector<string> values;
for(auto value : _allowedValues) values.append(value);
auto readAllowedValues() const -> std::vector<string> override {
std::vector<string> values;
for(auto value : _allowedValues) values.push_back(value);
return values;
}
auto writeValue(string value) -> void override { setValue(value.integer()); }
protected:
function<void (s64)> _modify;
std::function<void (s64)> _modify;
s64 _currentValue = {};
s64 _latchedValue = {};
vector<s64> _allowedValues;
std::vector<s64> _allowedValues;
};
+10 -10
View File
@@ -1,7 +1,7 @@
struct Natural : Setting {
DeclareClass(Natural, "setting.natural")
Natural(string name = {}, u64 value = {}, function<void (u64)> modify = {}) : Setting(name) {
Natural(string name = {}, u64 value = {}, std::function<void (u64)> modify = {}) : Setting(name) {
_currentValue = value;
_latchedValue = value;
_modify = modify;
@@ -11,10 +11,10 @@ struct Natural : Setting {
auto value() const -> u64 { return _currentValue; }
auto latch() const -> u64 { return _latchedValue; }
auto setModify(function<void (u64)> modify) { _modify = modify; }
auto setModify(std::function<void (u64)> modify) { _modify = modify; }
auto setValue(u64 value) -> void {
if(_allowedValues && !_allowedValues.find(value)) return;
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
_currentValue = value;
if(_dynamic) setLatch();
}
@@ -25,23 +25,23 @@ struct Natural : Setting {
modify(_latchedValue);
}
auto setAllowedValues(vector<u64> allowedValues) -> void {
auto setAllowedValues(std::vector<u64> allowedValues) -> void {
_allowedValues = allowedValues;
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
}
auto readValue() const -> string override { return value(); }
auto readLatch() const -> string override { return latch(); }
auto readAllowedValues() const -> vector<string> override {
vector<string> values;
for(auto value : _allowedValues) values.append(value);
auto readAllowedValues() const -> std::vector<string> override {
std::vector<string> values;
for(auto value : _allowedValues) values.push_back(value);
return values;
}
auto writeValue(string value) -> void override { setValue(value.natural()); }
protected:
function<void (u64)> _modify;
std::function<void (u64)> _modify;
u64 _currentValue = {};
u64 _latchedValue = {};
vector<u64> _allowedValues;
std::vector<u64> _allowedValues;
};
+10 -10
View File
@@ -1,7 +1,7 @@
struct Real : Setting {
DeclareClass(Real, "setting.real")
Real(string name = {}, f64 value = {}, function<void (f64)> modify = {}) : Setting(name) {
Real(string name = {}, f64 value = {}, std::function<void (f64)> modify = {}) : Setting(name) {
_currentValue = value;
_latchedValue = value;
_modify = modify;
@@ -11,10 +11,10 @@ struct Real : Setting {
auto value() const -> f64 { return _currentValue; }
auto latch() const -> f64 { return _latchedValue; }
auto setModify(function<void (f64)> modify) { _modify = modify; }
auto setModify(std::function<void (f64)> modify) { _modify = modify; }
auto setValue(f64 value) -> void {
if(_allowedValues && !_allowedValues.find(value)) return;
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
_currentValue = value;
if(_dynamic) setLatch();
}
@@ -25,23 +25,23 @@ struct Real : Setting {
modify(_latchedValue);
}
auto setAllowedValues(vector<f64> allowedValues) -> void {
auto setAllowedValues(std::vector<f64> allowedValues) -> void {
_allowedValues = allowedValues;
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
}
auto readValue() const -> string override { return value(); }
auto readLatch() const -> string override { return latch(); }
auto readAllowedValues() const -> vector<string> override {
vector<string> values;
for(auto value : _allowedValues) values.append(value);
auto readAllowedValues() const -> std::vector<string> override {
std::vector<string> values;
for(auto value : _allowedValues) values.push_back(value);
return values;
}
auto writeValue(string value) -> void override { setValue(value.real()); }
protected:
function<void (f64)> _modify;
std::function<void (f64)> _modify;
f64 _currentValue = {};
f64 _latchedValue = {};
vector<f64> _allowedValues;
std::vector<f64> _allowedValues;
};
+2 -2
View File
@@ -12,12 +12,12 @@ struct Setting : Object {
virtual auto readValue() const -> string { return {}; }
virtual auto readLatch() const -> string { return {}; }
virtual auto readAllowedValues() const -> vector<string> { return {}; }
virtual auto readAllowedValues() const -> std::vector<string> { return {}; }
virtual auto writeValue(string value) -> void {}
auto load(Node::Object source) -> bool override {
if(!Object::load(source)) return false;
if(auto setting = source->cast<shared_pointer<Setting>>()) writeValue(setting->readValue());
if(auto setting = source->cast<Node::Setting::Setting>()) writeValue(setting->readValue());
return true;
}
+8 -8
View File
@@ -1,7 +1,7 @@
struct String : Setting {
DeclareClass(String, "setting.string")
String(string name = {}, string value = {}, function<void (string)> modify = {}) : Setting(name) {
String(string name = {}, string value = {}, std::function<void (string)> modify = {}) : Setting(name) {
_currentValue = value;
_latchedValue = value;
_modify = modify;
@@ -11,10 +11,10 @@ struct String : Setting {
auto value() const -> string { return _currentValue; }
auto latch() const -> string { return _latchedValue; }
auto setModify(function<void (string)> modify) { _modify = modify; }
auto setModify(std::function<void (string)> modify) { _modify = modify; }
auto setValue(string value) -> void {
if(_allowedValues && !_allowedValues.find(value)) return;
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, value)) return;
_currentValue = value;
if(_dynamic) setLatch();
}
@@ -25,19 +25,19 @@ struct String : Setting {
modify(_latchedValue);
}
auto setAllowedValues(vector<string> allowedValues) -> void {
auto setAllowedValues(std::vector<string> allowedValues) -> void {
_allowedValues = allowedValues;
if(_allowedValues && !_allowedValues.find(_currentValue)) setValue(_allowedValues.first());
if(!_allowedValues.empty() && !std::ranges::count(_allowedValues, _currentValue)) setValue(_allowedValues.front());
}
auto readValue() const -> string override { return value(); }
auto readLatch() const -> string override { return latch(); }
auto readAllowedValues() const -> vector<string> override { return _allowedValues; }
auto readAllowedValues() const -> std::vector<string> override { return _allowedValues; }
auto writeValue(string value) -> void override { setValue(value); }
protected:
function<void (string)> _modify;
std::function<void (string)> _modify;
string _currentValue = {};
string _latchedValue = {};
vector<string> _allowedValues;
std::vector<string> _allowedValues;
};
+14 -14
View File
@@ -10,20 +10,20 @@ struct System : Object {
auto serialize(bool synchronize = true) -> serializer { if(_serialize) return _serialize(synchronize); return {}; }
auto unserialize(serializer& s) -> bool { if(_unserialize) return _unserialize(s); return false; }
auto setGame(function<string ()> game) -> void { _game = game; }
auto setRun(function<void ()> run) -> void { _run = run; }
auto setPower(function<void (bool)> power) -> void { _power = power; }
auto setSave(function<void ()> save) -> void { _save = save; }
auto setUnload(function<void ()> unload) -> void { _unload = unload; }
auto setSerialize(function<serializer (bool)> serialize) -> void { _serialize = serialize; }
auto setUnserialize(function<bool (serializer&)> unserialize) -> void { _unserialize = unserialize; }
auto setGame(std::function<string ()> game) -> void { _game = game; }
auto setRun(std::function<void ()> run) -> void { _run = run; }
auto setPower(std::function<void (bool)> power) -> void { _power = power; }
auto setSave(std::function<void ()> save) -> void { _save = save; }
auto setUnload(std::function<void ()> unload) -> void { _unload = unload; }
auto setSerialize(std::function<serializer (bool)> serialize) -> void { _serialize = serialize; }
auto setUnserialize(std::function<bool (serializer&)> unserialize) -> void { _unserialize = unserialize; }
protected:
function<string ()> _game;
function<void ()> _run;
function<void (bool)> _power;
function<void ()> _save;
function<void ()> _unload;
function<serializer (bool)> _serialize;
function<bool (serializer&)> _unserialize;
std::function<string ()> _game;
std::function<void ()> _run;
std::function<void (bool)> _power;
std::function<void ()> _save;
std::function<void ()> _unload;
std::function<serializer (bool)> _serialize;
std::function<bool (serializer&)> _unserialize;
};
+79
View File
@@ -0,0 +1,79 @@
struct Tape : Peripheral {
DeclareClass(Tape, "tape") using Peripheral::Peripheral;
~Tape() {
unload();
}
auto play() -> void { _playing = true; }
auto record() -> void { _recording = true; }
auto stop() -> void {
_playing = false;
_recording = false;
}
auto playing() const -> bool { return _playing; }
auto recording() const -> bool { return _recording; }
auto loaded() const -> bool { return _loaded; }
auto load() -> bool {
if (!_loaded && _load && _load()) {
_loaded = true;
return true;
}
return _loaded;
}
auto unload() -> void {
if (_loaded) {
stop();
if (_unload) _unload();
_loaded = false;
}
}
auto setLoad(std::function<bool()> load) -> void { _load = load; }
auto setUnload(std::function<void()> unload) -> void { _unload = unload; }
auto setSupportPlay(bool support) -> void { _supportPlay = support; }
auto setSupportRecord(bool support) -> void { _supportRecord = support; }
auto supportPlay() const -> bool { return _supportPlay; }
auto supportRecord() const -> bool { return _supportRecord; }
auto length() const -> u64 { return _length; }
auto setLength(u64 length) -> void { _length = length; }
auto position() const -> u64 { return _position; }
auto setPosition(u64 position) -> void { _position = position; }
auto frequency() const -> u64 { return _frequency; }
auto setFrequency(u64 frequency) -> void { _frequency = frequency; }
auto serialize(string &output, string depth) -> void override {
Peripheral::serialize(output, depth);
output.append(depth, " supportPlay: ", _supportPlay, "\n");
output.append(depth, " supportRecord: ", _supportRecord, "\n");
output.append(depth, " playing: ", _playing, "\n");
output.append(depth, " recording: ", _recording, "\n");
}
auto unserialize(Markup::Node node) -> void override {
Peripheral::unserialize(node);
_supportPlay = node["supportPlay"].boolean();
_supportRecord = node["supportRecord"].boolean();
_playing = node["playing"].boolean();
_recording = node["recording"].boolean();
}
private:
bool _supportPlay = false;
bool _supportRecord = false;
bool _playing = false;
bool _recording = false;
bool _loaded = false;
u64 _length = 0;
u64 _position = 0;
u64 _frequency = 1;
std::function<bool()> _load;
std::function<void()> _unload;
};
+66 -36
View File
@@ -1,15 +1,18 @@
#include <memory>
Screen::Screen(string name, u32 width, u32 height) : Video(name) {
_canvasWidth = width;
_canvasHeight = height;
if(width && height) {
_inputA = new u32[width * height]();
_inputB = new u32[width * height]();
_output = new u32[width * height]();
_rotate = new u32[width * height]();
_inputA = std::make_unique<u32[]>(width * height);
_inputB = std::make_unique<u32[]>(width * height);
_output = std::make_unique<u32[]>(width * height);
_rotate = std::make_unique<u32[]>(width * height);
_lineOverrideActive.resize(width * height, false);
_lineOverride.resize(width * height, nullptr);
if constexpr(ares::Video::Threaded) {
_thread = nall::thread::create({&Screen::main, this});
_thread = nall::thread::create(std::bind_front(&Screen::main, this));
}
}
}
@@ -24,6 +27,7 @@ Screen::~Screen() {
}
auto Screen::main(uintptr_t) -> void {
thread::setName("dev.ares.screen");
while(!_kill) {
unique_lock<mutex> lock(_frameMutex);
@@ -40,34 +44,37 @@ auto Screen::main(uintptr_t) -> void {
auto Screen::quit() -> void {
_kill = true;
_thread.join();
_sprites.reset();
_sprites.clear();
}
auto Screen::power() -> void {
lock_guard<recursive_mutex> lock(_mutex);
memory::fill<u32>(_inputA.data(), _canvasWidth * _canvasHeight, _fillColor);
memory::fill<u32>(_inputB.data(), _canvasWidth * _canvasHeight, _fillColor);
memory::fill<u32>(_output.data(), _canvasWidth * _canvasHeight, _fillColor);
memory::fill<u32>(_rotate.data(), _canvasWidth * _canvasHeight, _fillColor);
memory::fill<u32>(_inputA.get(), _canvasWidth * _canvasHeight, _fillColor);
memory::fill<u32>(_inputB.get(), _canvasWidth * _canvasHeight, _fillColor);
memory::fill<u32>(_output.get(), _canvasWidth * _canvasHeight, _fillColor);
memory::fill<u32>(_rotate.get(), _canvasWidth * _canvasHeight, _fillColor);
memory::fill<n1>(_lineOverrideActive.data(), _canvasWidth * _canvasHeight, false);
memory::fill<const u32*>(_lineOverride.data(), _canvasWidth * _canvasHeight, nullptr);
}
auto Screen::pixels(bool frame) -> array_span<u32> {
if(frame == 0) return {_inputA.data(), _canvasWidth * _canvasHeight};
if(frame == 1) return {_inputB.data(), _canvasWidth * _canvasHeight};
auto Screen::pixels(bool frame) -> std::span<u32> {
if(frame == 0) return {_inputA.get(), _canvasWidth * _canvasHeight};
if(frame == 1) return {_inputB.get(), _canvasWidth * _canvasHeight};
return {};
}
auto Screen::resetPalette() -> void {
lock_guard<recursive_mutex> lock(_mutex);
_palette.reset();
refreshPalette();
}
auto Screen::resetSprites() -> void {
lock_guard<recursive_mutex> lock(_mutex);
_sprites.reset();
_sprites.clear();
}
auto Screen::setRefresh(function<void ()> refresh) -> void {
auto Screen::setRefresh(std::function<void ()> refresh) -> void {
lock_guard<recursive_mutex> lock(_mutex);
_refresh = refresh;
}
@@ -116,18 +123,21 @@ auto Screen::setSaturation(f64 saturation) -> void {
lock_guard<recursive_mutex> lock(_mutex);
_saturation = saturation;
_palette.reset();
refreshPalette();
}
auto Screen::setGamma(f64 gamma) -> void {
lock_guard<recursive_mutex> lock(_mutex);
_gamma = gamma;
_palette.reset();
refreshPalette();
}
auto Screen::setLuminance(f64 luminance) -> void {
lock_guard<recursive_mutex> lock(_mutex);
_luminance = luminance;
_palette.reset();
refreshPalette();
}
auto Screen::setFillColor(u32 fillColor) -> void {
@@ -171,21 +181,22 @@ auto Screen::setInterlace(bool interlaceField) -> void {
auto Screen::attach(Node::Video::Sprite sprite) -> void {
lock_guard<recursive_mutex> lock(_mutex);
if(_sprites.find(sprite)) return;
_sprites.append(sprite);
if(std::ranges::find(_sprites, sprite) != _sprites.end()) return;
_sprites.push_back(sprite);
}
auto Screen::detach(Node::Video::Sprite sprite) -> void {
lock_guard<recursive_mutex> lock(_mutex);
if(!_sprites.find(sprite)) return;
_sprites.removeByValue(sprite);
if(std::ranges::find(_sprites, sprite) == _sprites.end()) return;
std::erase(_sprites, sprite);
}
auto Screen::colors(u32 colors, function<n64 (n32)> color) -> void {
auto Screen::colors(u32 colors, std::function<n64 (n32)> color) -> void {
lock_guard<recursive_mutex> lock(_mutex);
_colors = colors;
_color = color;
_palette.reset();
refreshPalette();
}
auto Screen::frame() -> void {
@@ -218,14 +229,20 @@ auto Screen::refresh() -> void {
auto pitch = _canvasWidth;
auto width = _canvasWidth;
auto height = _canvasHeight;
auto input = _inputB.data();
auto output = _output.data();
auto input = _inputB.get();
auto output = _output.get();
for(u32 y : range(height)) {
auto source = input + y * pitch;
auto target = output + y * width;
if(_interlace) {
if (_lineOverrideActive[y]) {
auto source = _lineOverride[y];
for(u32 x : range(width)) {
auto color = *source++;
*target++ = color;
}
} else if(_interlace) {
if((_interlaceField & 1) == (y & 1)) {
for(u32 x : range(width)) {
auto color = _palette[*source++];
@@ -294,11 +311,11 @@ auto Screen::refresh() -> void {
for(u32 y : range(height)) {
auto source = output + y * width;
for(u32 x : range(width)) {
auto target = _rotate.data() + (width - 1 - x) * height + y;
auto target = _rotate.get() + (width - 1 - x) * height + y;
*target = *source++;
}
}
output = _rotate.data();
output = _rotate.get();
swap(width, height);
swap(viewWidth, viewHeight);
}
@@ -308,11 +325,11 @@ auto Screen::refresh() -> void {
for(u32 y : range(height)) {
auto source = output + y * width;
for(u32 x : range(width)) {
auto target = _rotate.data() + (height - 1 - y) * width + (width - 1 - x);
auto target = _rotate.get() + (height - 1 - y) * width + (width - 1 - x);
*target = *source++;
}
}
output = _rotate.data();
output = _rotate.get();
}
if(_rotation == 270) {
@@ -320,17 +337,31 @@ auto Screen::refresh() -> void {
for(u32 y : range(height)) {
auto source = output + y * width;
for(u32 x : range(width)) {
auto target = _rotate.data() + x * height + (height - 1 - y);
auto target = _rotate.get() + x * height + (height - 1 - y);
*target = *source++;
}
}
output = _rotate.data();
output = _rotate.get();
swap(width, height);
swap(viewWidth, viewHeight);
}
platform->video(shared(), output + viewX + viewY * width, width * sizeof(u32), viewWidth, viewHeight);
memory::fill<u32>(_inputB.data(), width * height, _fillColor);
platform->video(std::static_pointer_cast<Core::Video::Screen>(shared_from_this()), output + viewX + viewY * width, width * sizeof(u32), viewWidth, viewHeight);
memory::fill<u32>(_inputB.get(), width * height, _fillColor);
}
auto Screen::lookupPalette(u32 index) -> u32 {
return _palette[index];
}
auto Screen::overrideLineDraw(u32 y, const u32* source) -> void {
_lineOverride[y] = source;
_lineOverrideActive[y] = true;
}
auto Screen::clearOverrideLineDraw(u32 y) -> void {
_lineOverrideActive[y] = false;
_lineOverride[y] = nullptr;
}
auto Screen::refreshPalette() -> void {
@@ -338,7 +369,7 @@ auto Screen::refreshPalette() -> void {
if(_palette) return;
//generate the color lookup palettes to convert native colors to ARGB8888
_palette = new u32[_colors];
_palette = std::make_unique<u32[]>(_colors);
for(u32 index : range(_colors)) {
n64 color = _color(index);
n16 b = color.bit( 0,15);
@@ -348,10 +379,9 @@ auto Screen::refreshPalette() -> void {
if(_saturation != 1.0) {
n16 grayscale = uclamp<16>((r + g + b) / 3);
f64 inverse = max(0.0, 1.0 - _saturation);
r = uclamp<16>(r * _saturation + grayscale * inverse);
g = uclamp<16>(g * _saturation + grayscale * inverse);
b = uclamp<16>(b * _saturation + grayscale * inverse);
r = uclamp<16>(grayscale + (r - grayscale) * _saturation);
g = uclamp<16>(grayscale + (g - grayscale) * _saturation);
b = uclamp<16>(grayscale + (b - grayscale) * _saturation);
}
if(_gamma != 1.0) {
+16 -11
View File
@@ -18,7 +18,7 @@ struct Screen : Video {
auto aspectY() const -> f64 { return _aspectY; }
auto overscan() const -> bool { return _overscan; }
auto colors() const -> u32 { return _colors; }
auto pixels(bool frame = 0) -> array_span<u32>;
auto pixels(bool frame = 0) -> std::span<u32>;
auto saturation() const -> double { return _saturation; }
auto gamma() const -> double { return _gamma; }
@@ -32,7 +32,7 @@ struct Screen : Video {
auto resetPalette() -> void;
auto resetSprites() -> void;
auto setRefresh(function<void ()> refresh) -> void;
auto setRefresh(std::function<void ()> refresh) -> void;
auto setViewport(u32 x, u32 y, u32 width, u32 height) -> void;
auto refreshRateHint(double refreshRate) -> void;
auto refreshRateHint(double pixelFrequency, int dotsPerLine, int linesPerFrame) -> void;
@@ -58,9 +58,12 @@ struct Screen : Video {
auto attach(Node::Video::Sprite) -> void;
auto detach(Node::Video::Sprite) -> void;
auto colors(u32 colors, function<n64 (n32)> color) -> void;
auto colors(u32 colors, std::function<n64 (n32)> color) -> void;
auto frame() -> void;
auto refresh() -> void;
auto lookupPalette(u32 index) -> u32;
auto overrideLineDraw(u32 y, const u32* source) -> void;
auto clearOverrideLineDraw(u32 y) -> void;
auto serialize(string& output, string depth) -> void override;
auto unserialize(Markup::Node node) -> void override;
@@ -88,13 +91,15 @@ protected:
bool _overscan = true;
u32 _rotation = 0; //counter-clockwise (90 = left, 270 = right)
function<n64 (n32)> _color;
unique_pointer<u32[]> _inputA;
unique_pointer<u32[]> _inputB;
unique_pointer<u32[]> _output;
unique_pointer<u32[]> _rotate;
unique_pointer<u32[]> _palette;
vector<Node::Video::Sprite> _sprites;
std::function<n64 (n32)> _color;
std::unique_ptr<u32[]> _inputA;
std::unique_ptr<u32[]> _inputB;
std::unique_ptr<u32[]> _output;
std::unique_ptr<u32[]> _rotate;
std::unique_ptr<u32[]> _palette;
std::vector<n1> _lineOverrideActive;
std::vector<const u32*> _lineOverride;
std::vector<Node::Video::Sprite> _sprites;
//unserialized:
nall::thread _thread;
@@ -103,7 +108,7 @@ protected:
condition_variable _frameCondition;
atomic<bool> _kill = false;
atomic<bool> _frame = false;
function<void ()> _refresh;
std::function<void ()> _refresh;
bool _progressive = false;
bool _progressiveDouble = false;
bool _interlace = false;
+3 -3
View File
@@ -10,13 +10,13 @@ auto Sprite::setPosition(u32 x, u32 y) -> void {
auto Sprite::setImage(nall::image image, bool invert) -> void {
_width = image.width();
_height = image.height();
_pixels = new u32[_width * _height];
_pixels = std::make_unique<u32[]>(_width * _height);
image.transform(0, 32, 255u << 24, 255u << 16, 255u << 8, 255u << 0);
memory::copy(_pixels.data(), _width * _height * sizeof(u32), image.data(), image.size());
memory::copy(_pixels.get(), _width * _height * sizeof(u32), image.data(), image.size());
if(!invert) return;
for(u32 y : range(_height)) {
auto data = _pixels.data() + y * _width;
auto data = _pixels.get() + y * _width;
for(u32 x : range(_width)) {
auto pixel = data[x];
pixel ^= 0xffffff;
+2 -2
View File
@@ -7,7 +7,7 @@ struct Sprite : Video {
auto y() const -> u32 { return _y; }
auto width() const -> u32 { return _width; }
auto height() const -> u32 { return _height; }
auto image() const -> array_view<u32> { return {_pixels.data(), _width * _height}; }
auto image() const -> std::span<const u32> { return {_pixels.get(), _width * _height}; }
auto setVisible(bool visible) -> void;
auto setPosition(u32 x, u32 y) -> void;
@@ -19,5 +19,5 @@ protected:
u32 _y = 0;
u32 _width = 0;
u32 _height = 0;
unique_pointer<u32[]> _pixels;
std::unique_ptr<u32[]> _pixels;
};
+4 -1
View File
@@ -8,12 +8,15 @@ enum class Event : u32 {
Frame,
Power,
Synchronize,
FastForwardOn,
FastForwardOff,
Shutdown
};
struct Platform {
virtual auto attach(Node::Object) -> void {}
virtual auto detach(Node::Object) -> void {}
virtual auto pak(Node::Object) -> shared_pointer<vfs::directory> { return {}; }
virtual auto pak(Node::Object) -> std::shared_ptr<vfs::directory> { return {}; }
virtual auto event(Event) -> void {}
virtual auto log(Node::Debugger::Tracer::Tracer, string_view message) -> void {}
virtual auto status(string_view message) -> void {}
+13 -5
View File
@@ -4,6 +4,9 @@ namespace ares {
struct Random {
enum class Entropy : u32 { None, Low, High };
struct Init { u64 seed, sequence; };
static constexpr Init Default { 0x853c49e6748fea9b, 0xda3e39cb94b95bdb };
auto operator()() -> n64 {
return random();
@@ -14,8 +17,8 @@ struct Random {
seed();
}
auto seed(maybe<n32> seed = nothing, maybe<n32> sequence = nothing) -> void {
if(!seed) seed = (n32)clock();
auto seed(maybe<n64> seed = nothing, maybe<n64> sequence = nothing) -> void {
if(!seed) seed = (n64)clock();
if(!sequence) sequence = 0;
_state = 0;
@@ -25,6 +28,10 @@ struct Random {
step();
}
auto seed(Init init) -> void {
seed((n64)init.seed, (n64)init.sequence);
}
auto random() -> n64 {
if(_entropy == Entropy::None) return 0;
return (n64)step() << 32 | (n64)step() << 0;
@@ -43,15 +50,16 @@ struct Random {
}
}
auto array(array_span<n8> buffer) -> void {
auto array(std::span<u8> buffer) -> void {
if(_entropy == Entropy::None) {
memory::fill(buffer.data(), buffer.size());
return;
}
if(_entropy == Entropy::High) {
for(n32 address : range(buffer.size())) {
buffer[address] = random();
while(buffer.size()) {
u64 value = random();
nall::writel(buffer, value, min((u32)sizeof(value), (u32)buffer.size()));
}
return;
}
-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];
}
}
}
+4 -4
View File
@@ -1,5 +1,5 @@
inline auto Scheduler::reset() -> void {
_threads.reset();
_threads.clear();
}
inline auto Scheduler::threads() const -> u32 {
@@ -41,15 +41,15 @@ inline auto Scheduler::maximum() const -> u64 {
}
inline auto Scheduler::append(Thread& thread) -> bool {
if(_threads.find(&thread)) return false;
if(std::ranges::find(_threads, &thread) != _threads.end()) return false;
thread._uniqueID = uniqueID();
thread._clock = maximum() + thread._uniqueID;
_threads.append(&thread);
_threads.push_back(&thread);
return true;
}
inline auto Scheduler::remove(Thread& thread) -> void {
_threads.removeByValue(&thread);
std::erase(_threads, &thread);
}
//power cycle and soft reset events: assigns the primary thread and resets all thread clocks.
+1 -1
View File
@@ -38,7 +38,7 @@ private:
cothread_t _primary = nullptr; //primary thread (used to synchronize components)
Mode _mode = Mode::Run;
Event _event = Event::Step;
vector<Thread*> _threads;
std::vector<Thread*> _threads;
bool _synchronize = false;
friend struct Thread;
+7 -7
View File
@@ -1,5 +1,5 @@
inline auto Thread::EntryPoints() -> vector<EntryPoint>& {
static vector<EntryPoint> entryPoints;
inline auto Thread::EntryPoints() -> std::vector<EntryPoint>& {
static std::vector<EntryPoint> entryPoints;
return entryPoints;
}
@@ -7,7 +7,7 @@ inline auto Thread::Enter() -> void {
for(u32 index : range(EntryPoints().size())) {
if(co_active() == EntryPoints()[index].handle) {
auto entryPoint = EntryPoints()[index].entryPoint;
EntryPoints().remove(index);
EntryPoints().erase(EntryPoints().begin() + index);
while(true) {
scheduler.synchronize();
entryPoint();
@@ -45,22 +45,22 @@ inline auto Thread::setClock(u64 clock) -> void {
_clock = clock;
}
inline auto Thread::create(double frequency, function<void ()> entryPoint) -> void {
inline auto Thread::create(double frequency, std::function<void ()> entryPoint) -> void {
if(!_handle) {
_handle = co_create(Thread::Size, &Thread::Enter);
} else {
co_derive(_handle, Thread::Size, &Thread::Enter);
}
EntryPoints().append({_handle, entryPoint});
EntryPoints().push_back({_handle, entryPoint});
setFrequency(frequency);
setClock(0);
scheduler.append(*this);
}
//returns a thread to its entry point (eg for a reset), without resetting the clock value
inline auto Thread::restart(function<void()> entryPoint) -> void {
inline auto Thread::restart(std::function<void()> entryPoint) -> void {
co_derive(_handle, Thread::Size, &Thread::Enter);
EntryPoints().append({_handle, entryPoint});
EntryPoints().push_back({_handle, entryPoint});
}
inline auto Thread::destroy() -> void {
+4 -4
View File
@@ -6,10 +6,10 @@ struct Thread {
struct EntryPoint {
cothread_t handle = nullptr;
function<void ()> entryPoint;
std::function<void ()> entryPoint;
};
static auto EntryPoints() -> vector<EntryPoint>&;
static auto EntryPoints() -> std::vector<EntryPoint>&;
static auto Enter() -> void;
Thread() = default;
@@ -29,8 +29,8 @@ struct Thread {
auto setScalar(u64 scalar) -> void;
auto setClock(u64 clock) -> void;
auto create(double frequency, function<void ()> entryPoint) -> void;
auto restart(function<void ()> entryPoint) -> void;
auto create(double frequency, std::function<void ()> entryPoint) -> void;
auto restart(std::function<void ()> entryPoint) -> void;
auto destroy() -> void;
auto step(u32 clocks) -> void;
+15
View File
@@ -1,5 +1,9 @@
list(REMOVE_DUPLICATES ares.components)
set(ARES_COMPONENTS_LIST "${ares.components}" CACHE STRING "Enabled shared hardware components" FORCE)
mark_as_advanced(ARES_COMPONENTS_LIST)
ares_add_sources(INCLUDED CMakeLists.txt)
macro(component_sources)
@@ -134,6 +138,7 @@ component_sources(
INCLUDED
processor/arm7tdmi/algorithms.cpp
processor/arm7tdmi/arm7tdmi.hpp
processor/arm7tdmi/coprocessor.cpp
processor/arm7tdmi/disassembler.cpp
processor/arm7tdmi/instruction.cpp
processor/arm7tdmi/instructions-arm.cpp
@@ -432,6 +437,16 @@ component_sources(
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
-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
+4 -2
View File
@@ -135,10 +135,10 @@ auto YM2149::read() -> n8 {
data.bit(4,7) = envelope.unused;
break;
case 14:
data.bit(0,7) = portA.data;
data.bit(0,7) = readIO(0);
break;
case 15:
data.bit(0,7) = portB.data;
data.bit(0,7) = readIO(1);
break;
}
@@ -215,9 +215,11 @@ auto YM2149::write(n8 data) -> void {
break;
case 14:
portA.data = data;
writeIO(0, data);
break;
case 15:
portB.data = data;
writeIO(1, data);
break;
}
}
+3
View File
@@ -5,6 +5,9 @@ namespace ares {
//Yamaha YM2149 (General Instrument AY-3-8910 derivative)
struct YM2149 {
virtual auto readIO(n1 port) -> n8 { return 0xff; }
virtual auto writeIO(n1 port, n8 data) -> void {}
//ym2149.cpp
auto clock() -> array<n5[3]>;
auto read() -> n8;
+2 -2
View File
@@ -125,7 +125,7 @@ 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;
@@ -147,7 +147,7 @@ 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;
+5 -9
View File
@@ -36,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);
@@ -125,10 +121,10 @@ auto YM2612::writeData(n8 data) -> void {
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,7 @@ 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);
+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;
}
+3 -1
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,7 @@ protected:
n1 keyOn = 0;
n1 keyLine = 0;
n1 lfoEnable = 0;
n1 tremoloEnable = 0;
n5 keyScale = 0;
n3 detune = 0;
n4 multiple = 0;
+1 -1
View File
@@ -15,7 +15,7 @@ auto M24C::serialize(serializer& s) -> void {
s(output);
s(response);
s(writable);
s(array_span<u8>{memory, size()});
s(std::span<n8>{memory, size()});
if(type >= Type::M24C32) s(idpage);
s(locked);
}
+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;
+58 -28
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;
@@ -44,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;
@@ -70,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;
@@ -133,7 +136,7 @@ struct ARM7TDMI {
}
n32 data;
function<auto () -> void> modify;
std::function<auto () -> void> modify;
};
struct PSR {
@@ -148,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;
@@ -174,6 +187,8 @@ struct ARM7TDMI {
b1 c; //carry
b1 z; //zero
b1 n; //negative
b1 readonly;
};
struct Processor {
@@ -182,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;
@@ -221,7 +238,6 @@ struct ARM7TDMI {
};
n1 reload = 1;
n1 nonsequential = 1;
Instruction fetch;
Instruction decode;
Instruction execute;
@@ -230,27 +246,41 @@ struct ARM7TDMI {
n32 opcode;
b1 carry;
b1 irq;
b1 nonsequential;
function<void (n32 opcode)> armInstruction[4096];
function<void ()> thumbInstruction[65536];
std::function<void (n32 opcode)> armInstruction[4096];
std::function<void ()> thumbInstruction[65536];
//coprocessor.cpp
auto bindCDP(n4 id, std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void;
auto bindMCR(n4 id, std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
auto bindMRC(n4 id, std::function<n32 (n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void;
std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> CDP[16];
std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> MCR[16];
std::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;
@@ -280,8 +310,8 @@ struct ARM7TDMI {
auto thumbDisassembleStackMultiple(n8, n1, n1) -> string;
auto thumbDisassembleUndefined() -> string;
function<string (n32 opcode)> armDisassemble[4096];
function<string ()> thumbDisassemble[65536];
std::function<string (n32 opcode)> armDisassemble[4096];
std::function<string ()> thumbDisassemble[65536];
n32 _pc;
string _c;
@@ -0,0 +1,11 @@
auto ARM7TDMI::bindCDP(n4 id, std::function<void (n4 cm, n3 op2, n4 cd, n4 cn, n4 op1)> handler) -> void {
CDP[id] = handler;
}
auto ARM7TDMI::bindMCR(n4 id, std::function<void (n32 data, n4 cm, n3 op2, n4 cn, n3 op1)> handler) -> void {
MCR[id] = handler;
}
auto ARM7TDMI::bindMRC(n4 id, std::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)};
}
+135 -64
View File
@@ -1,11 +1,9 @@
auto ARM7TDMI::reload() -> void {
u32 mask = !cpsr().t ? 3 : 1;
u32 size = !cpsr().t ? Word : Half;
pipeline.reload = false;
r(15).data &= ~mask;
pipeline.fetch.address = r(15) & ~mask;
pipeline.fetch.instruction = read(Prefetch | size | Nonsequential, pipeline.fetch.address);
endBurst();
pipeline.fetch.address = r(15);
pipeline.fetch.instruction = read(Prefetch | size, pipeline.fetch.address);
fetch();
}
@@ -16,18 +14,10 @@ auto ARM7TDMI::fetch() -> void {
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 {
@@ -85,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 */ \
@@ -143,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
@@ -287,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
@@ -310,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
@@ -326,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
@@ -358,22 +415,35 @@ 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 {
#define bind(id, name, ...) { \
assert(!thumbInstruction[id]); \
thumbInstruction[id] = [=] { return thumbInstruction##name(__VA_ARGS__); }; \
thumbDisassemble[id] = [=] { return thumbDisassemble##name(__VA_ARGS__); }; \
thumbInstruction[id] = [=, this] { return thumbInstruction##name(__VA_ARGS__); }; \
thumbDisassemble[id] = [=, this] { return thumbDisassemble##name(__VA_ARGS__); }; \
}
#define pattern(s) \
@@ -423,9 +493,9 @@ auto ARM7TDMI::thumbInitialize() -> void {
bind(opcode, AdjustStack, immediate, mode);
}
for(n4 d : range(16))
for(n4 _ : range(16))
for(n4 m : range(16)) {
auto opcode = pattern("0100 0111 ???? ?---") | d.bit(0,2) << 0 | m << 3 | d.bit(3) << 7;
auto opcode = pattern("0100 0111 ???? ?---") | _.bit(0,2) << 0 | m << 3 | _.bit(3) << 7;
bind(opcode, BranchExchange, m);
}
@@ -446,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,84 +86,65 @@ 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 {
lock();
n32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
r(d) = word;
n32 word = load((byte ? Byte : Word), r(n));
store((byte ? Byte : Word), r(n), r(m) + (m == 15 ? 4 : 0));
unlock();
idle();
r(d) = word;
}
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(mode == 1) r(d) = rd;
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
if(mode == 1) {
idle();
r(d) = rd;
}
}
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(mode == 1) r(d) = rd;
if(pre == 0 || writeback) r(n) = rn + (n == 15 ? 4 : 0);
if(mode == 1) {
idle();
r(d) = rd;
}
}
auto ARM7TDMI::armInstructionMoveImmediateOffset
@@ -173,46 +153,47 @@ 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;
if(mode == 1) r(d) = rd;
if(mode == 1) {
idle();
r(d) = rd;
}
}
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;
@@ -223,19 +204,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;
@@ -247,12 +223,67 @@ 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;
if(mode == 1) {
idle();
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) {
idle();
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) {
idle();
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
@@ -268,14 +299,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
@@ -302,8 +344,8 @@ auto ARM7TDMI::armInstructionMultiplyLong
n64 rd = rm * rs;
if(accumulate) rd += (n64)r(h) << 32 | (n64)r(l) << 0;
r(l) = rd >> 0;
r(h) = rd >> 32;
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,81 @@ 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);
idle();
}
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); idle(); 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); idle(); 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)); idle(); break; //LDSB
case 4: r(d) = load(Word, r(n) + r(m)); idle(); break; //LDR
case 5: r(d) = load(Half, r(n) + r(m)); idle(); break; //LDRH
case 6: r(d) = load(Byte, r(n) + r(m)); idle(); break; //LDRB
case 7: r(d) = load(Half | Signed, r(n) + r(m)); idle(); 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); idle(); 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); idle(); break; //LDR
}
}
@@ -198,33 +200,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 -7
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;
@@ -23,17 +25,17 @@ auto ARM7TDMI::load(u32 mode, n32 address) -> n32 {
} else {
word = ROR(word, address.bit(0,1) << 3);
}
idle();
return word;
}
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,11 +57,11 @@ 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);
Loaded 100 of 6416 files, more files were not shown because too many files have changed in this diff. Show more