Commit Graph
7 Commits
Author SHA1 Message Date
LibretroAdmin 4dedef028b Memory: convert to C89, with the memory map and handler APIs it faces
Memory.c and VirtualMemory.c replace their C++ originals: the memory
managers, bump allocator and reserves are plain structs and functions,
SysMainMemory is a struct, the host memory map is HOSTMEM_ constants,
and the GS JIT's code reserve is GSCodeReserve.c. The vtlb, GS, DEV9,
CDVD NVRAM, IOP and MTVU entry points Memory.c calls carry C linkage;
the EE hardware handler sets are registered from Dmac.cpp, so Hw.cpp's
handlers stay as they are.

memBindConditionalHandlers takes the INTC_STAT hack and MTVU setting
and binds VU1's memory handlers for them, so no handler tests the
configuration per access, and MTVU writes store straight into their
ring slot. The main and code maps are placed together by
near_place_pair: the shared-memory backing is created once, a taken
address fails with one MAP_FIXED_NOREPLACE call, the bases next to the
image are tried before the address space is read, and it is read at
most once.
2026-10-27 11:41:24 +01:00
LibretroAdmin 3660a1fe8b tests: the console-capture harnesses build against the tree
The EE, VIF and IOP suites that score the interpreters against
ps2autotests and ps1-tests captures build and run again:

- tests/ee: the COP2 macro-mode stubs carry C linkage, as COP2.c gives
  the ops they stand in for; the scratchpad harness includes Config.h
  for the configuration it sizes, and its DMAC stubs take the channel
  by pointer.
- tests/vif: the unpack harness includes Config.h.
- tests/iop: the GTE is compiled as C on its own and linked into the
  interpreter harness, as the GTE fuzz lane already does.

Their build products are ignored, as tests/iop's are.
2026-10-12 15:40:25 +02:00
LibretroAdmin 3dbf24a6d4 tests/cheaders: derive the header set, and check aarch64 and MSVC C
The lane that exists to stop exactly this kept a hand-written list of
headers. SingleRegisterTypes.h and VUmicro.h were not on it, so the two
C++-only spellings that broke Android arm64, Linux aarch64, macOS arm64,
webOS aarch64 and MSVC passed it. A list of what to check is a list of
what someone remembered.

The set is derived now, from the compiler's own dependency output for
every C unit: 74 headers, up from the 19 that were listed. Two entries
are include fragments spliced into the middle of one unit each rather
than headers, and are named as such.

Three things are checked that were not:

  - aarch64, for headers and for whole C units. The headers carry an
    arch-conditional half that an x86 pass never opens, which is where
    both of these bugs lived.

  - MSVC's C front end, for a static-storage initializer that names
    another const. C says a const object is not a constant expression;
    MSVC enforces it, gcc and clang do not, even at -pedantic-errors.
    No flag here reproduces it, so the preprocessed C view of each
    header is searched for the spelling. This is the VUmicro.h break.

  - every C unit at -Wall -Wextra on both arches, not just the four the
    savestate conversion happened to touch.

Checked against the broken headers: the lane reports both failures and
names the MSVC rule.

Also fixes tests/ee, which has been failing on master since SaveState
became C: hwgslabel, hwrealee and hwspr still defined the removed
SaveStateBase::FreezeMem and ::FreezeTag methods. They stub the C
functions now. tests/ipu/stubs.cpp defined the same two and is not
referenced by any lane, so it is deleted.
2026-09-22 03:21:25 +02:00
libretroadmin b819ef8142 tests: record why the DMAC tag interrupt is not scored
tests/dma/dmac/tagintr.expected builds a three-tag source chain and runs
it four times with the channel's TIE bit and the first tag's IRQ bit each
on and off. Only when both are set does the transfer stop early -- TADR
advances 0x10 in that case and 0x20 in the other three -- so the four
cases exist to pin that the condition is an and rather than either bit
alone. It is spr1ch.chcr.TIE && ptag->IRQ in _SPR1chain, and it reads
correctly.

I wrote the scorer and did not ship it. Driving the chain needs the real
hwDmacSrcChain, which is what advances TADR; this harness stubs that
function, since the interleave path never calls it, and with the stub in
place all four cases report TADR unmoved. The test would have been
measuring the stub. Linking Hw.cpp for the real one pulls in about sixty
further symbols -- the whole hardware register dispatch -- which is a poor
trade for four cases and would put most of the emulator behind a test of
one boolean.

Second time in three commits that a scorer has been written and discarded,
and the reason is the same both times: a harness that cannot reach the
code under test does not become useful by reporting a number. The
inspection is recorded where the next reader will look for it.
2026-08-28 22:55:27 +02:00
libretroadmin a29b73f01a tests: record what spr/normal claims, and why it is not scored
tests/dma/spr/normal.expected is about the DMA registers rather than the
transfer: SADR keeps bits 4 to 13, so its 0x81234028 reads back as 0x20,
and MADR drops bit 31, which is why its own harness reports that the
transfer "did not accept MADR: 80000000". Dmac.cpp's write path applies
0x3FF0 and 0x7FFFFFFF, so both claims hold; that was checked by reading
it.

I wrote it as a scored check first and threw that away. The cases were
"input & mask == expected" with the mask copied out of Dmac.cpp and the
expected value copied out of the capture, which compares two constants I
had transcribed and can only fail if I mistyped one. It passed 6 of 6 and
proved nothing about the emulator: driving the real write path needs the
hardware register file and its dispatch, which this harness does not have.

So it is recorded as an inspection instead. That is the same call already
made in this series for the arm64 switch dispatch and the MDEC status
register -- an inspection recorded as an inspection is worth more than a
check that cannot fail, and a score of 6 of 6 sitting in the output would
have implied coverage nothing was providing.
2026-08-28 22:30:39 +02:00
libretroadmin 38c5325c2e tests: score the scratchpad interleave downloads as well
Completes the capture: 240 upload rows becomes 448 across both
directions, so tests/dma/spr/interleave.expected is now read in full.

The two directions are separate functions and are mutation-checked
separately. _SPR0interleave reads the scratchpad and writes main memory
while _SPR1interleave does the reverse, and a mistake in one says nothing
about the other: making madr skip by SQWC alone fails 29 upload rows and
48 download ones, and making sadr skip as well fails 41 and 25. Sharing
the harness between them is fine; sharing the evidence would not be.

The TQWC == 0 mutation still survives on both sides, for the same reason
as before -- no case leaves TQWC zero on its own -- and the header now
says so for the pair rather than for the uploads alone.
2026-08-28 22:22:56 +02:00
libretroadmin 21e05a7270 tests: score the scratchpad DMA interleave uploads
tests/dma/spr/interleave.expected is the largest capture outside the cpu
tree and nothing read it. Interleave mode transfers TQWC quadwords, skips
SQWC and repeats; the capture prefills the destination with 0xcccccccc so
the untouched gaps are as visible as the written runs. 240 rows across the
fifteen upload configurations, driven through _SPR1interleave in SPR.cpp
with eeMem and the scratchpad as real arrays.

Making madr skip by SQWC alone rather than SQWC plus the transfer fails 29
rows; making sadr skip as well as madr fails 41. Only one of the two
addresses advances across a gap, and that is what these rows pin.

A third mutation survives and the header says so: changing the TQWC == 0
default from qwc to 1 leaves all 240 passing, because no upload case
leaves TQWC zero on its own. The downloads are not scored either.

Three modelling mistakes on the way, each of which looked like an emulator
bug first. The capture's headings are labels rather than parameters -- two
of them disagree with the values passed beside them in interleave.cpp --
so the parameters are taken from the source and matched by title. The
source buffer is filled per word with its own low byte, not per quadword,
and filling it per quadword scores 173 of 240. And the row label is a word
index, not a quadword one, so scaling it reads four times too far in and
scores 188 of 240 -- which reads as a short transfer rather than a misread
label.
2026-08-28 22:10:42 +02:00