43 Commits
Author SHA1 Message Date
libretroadmin f6f0106dfe C89: the Maple host and the modem's DNS lookups
maple_if.c drives the devices through a small C API in maple_if.h
(maple_dev_dma, maple_dev_has_slots, maple_dev_lightgun_pos,
maple_dev_flush_save), which also declares the I/O boards' state parts
and the mcfg_* calls once, with C linkage. A device writes its answer
straight into the room maple_out keeps for it until the transfer ends;
the copy is left only for when that room has run out.

dns.c builds its query and reads the answer as bytes, with no picoTCP
headers: dns_query_build() and dns_answer_parse() are tested on their
own by tools/modem/dns_run.sh (with the sanitizers, in headless.yml),
names too long for the query included.
2026-11-13 10:55:22 +01:00
LibretroAdmin c652c082c2 pvr/spg: a frame ends where the game renders, or reads its pads, after its vertical blank in interrupt
A retro_run - where the frontend reads its pad and shows the picture -
ended at line 0. Most games start the render of the frame they have
made, and read their pads, in their vertical blank in interrupt, which
need not be there:

- Sega Rally 2 (Windows CE) has its interrupt at line 0 and starts its
  render a line after it: that render was the first thing in the next
  run, and its picture was shown at that run's end, a frame after the
  game started it.
- Virtua Fighter 3tb and Jet Grind Radio have theirs at line 260: they
  render, then read the pads. Read in the middle of a run, the pads were
  read a run before the render that answered them could end one.

Now a run may end in the lines after the vertical blank in interrupt
(32, and never on or past the vertical blank out line, where the
hardware's maple transfer reads the pads): at a render to the screen the
game starts there - its picture is shown at once - or, before one, at a
maple transfer the game starts there, which is then made at the start of
the next run, with that run's pad. No time goes by between two runs, so
the transfer is made where the machine stands, as the game started it;
only the processor's last few hundred cycles of its time slice run before
it. A run that ended in a window ends in the next one, at either, or at
the window's end in a frame with neither (a game at 30 frames a second, a
loading screen), unless it rendered to the screen elsewhere in that frame:
then it goes on to line 0, where the runs of a game that does nothing in
the window (renders mid-frame, has the hardware read its pads) end as
before - but not past the next window: where line 0 came while the window
was open (Sega Rally 2's interrupt is at line 0), it ends at the window's
end. Each run has one vertical blank in interrupt in it. A window closed
early has the line event aimed again: one aimed at its end and taken for
a later line lost lines - a frame 13 lines (Sega Rally 2) or 233 lines
(Jet Grind Radio) short.

Measured with tools/lag: machine frames from the press to the first
picture that differs, RetroArch's default ("late") polling, the same
with threaded rendering on; this core before / after, and upstream
flycast with "Delay Frame Swapping" on (its default) / off, from states
each core made by booting the game the same way:

  Sega Rally 2, title, START          4 / 3      upstream 4 / 3
  Virtua Fighter 3tb, attract, START  3 / 2      upstream 3 / 2
  Jet Grind Radio, title, START       3-4 / 2-3  upstream 5 / 3
  Dead or Alive 2 Millennium, START   1 / 1      upstream 4 / 3
  Jet Grind Radio, street (s10), jump 3-4 / 2-3
  Jet Grind Radio, graffiti (s9), jump 3-4 / 2-3
  Virtua Fighter 4, START; DOA2, COIN 1-2 / 1-2  (they render before their
                                                 interrupt and read their
                                                 pads after line 0)

(Jet Grind Radio runs at 30 frames a second: the lag depends on which of
its two frames the press comes in, and is one frame less in the one of
them that was the longer.)

Where a run ends is decided by the machine alone, the same however the
frame is shown or not (a frame run ahead, fast-forward's frameskip): a
run starting in a window is one that ended in a window, a transfer
waiting for the next run is one started with nothing scheduled to end it
(it is made at the start of the next run, whether or not a state was
loaded in between), no run ends with the window open (dc_run()'s
backstop closes it too), and whether the game has started a render since
the last vertical blank - which the vertical blank goes by to show a
framebuffer the game wrote itself, and which was never so at line 0 - is
now in the state: bit 1 of pvr_serialize_v22()'s first byte, 0 in every
state before, which a state saved at line 0 has too. The state's size is
the same, and old states load as before. Without that bit, a frame run
ahead on the live test disc, which writes its framebuffer itself, was not
the frame run straight through (tools/threads/headless.sh).

tools/determinism (plain, again, reload, run-ahead, rollback, and frames
not shown, every one or RetroArch's run-ahead way) passes with threaded
rendering on and off on Jet Grind Radio, Sega Rally 2, Virtua Fighter
3tb, Virtua Fighter 4, Dead or Alive 2 and the live test disc;
tools/threads/headless.sh passes; tools/lag/samestep.sh has every
renderer in step on Jet Grind Radio, Sega Rally 2, Virtua Fighter 4 and
Dead or Alive 2. The sound each retro_run makes stays a frame's on
average, with no drift: over 1800 frames 735/736 samples a run in the
Dreamcast games and 737/738 in the NAOMI ones, as before; Sega Rally 2
alternates 713-718 and 754-759 where it renders every other frame (the
run ends at its render one frame and at the window's end the next), and
the first run after loading a state saved at line 0 is shorter, once.

A frame is a duplicate (video_cb with no picture) when no picture was
made in its run: a render to the screen or of the framebuffer the game
wrote itself. That was asked of the vblank, which no longer always ends
the run; a render to a texture alone no longer counts as a new picture.
2026-10-24 06:01:45 +02:00
LibretroAdmin 1780a0c2f2 maple, spg: the light gun's transfer no longer owed its end after an occupy cancel
A maple occupy cancel (MP_SDCKBOccupyCancel) dropped the light gun's
occupy but left the gun's transfer marked as owed its end at vblank-out,
as upstream clears it; spg_gun_occupy_cancel() clears it, and the
transfer ends at its own time.
2026-10-14 20:40:59 +02:00
LibretroAdmin 5f0bc7f4b5 naomi: cartridge reset on a hard reset, LUT names, network packet number
- A hard reset now resets the cartridge's registers - PIO and DMA
  offsets, M1 decompression and decryption state, M4 and Atomiswave
  device state, the GD-ROM cartridge's DIMM address - without reloading
  ROMs, and any reset clears the I/O board program buffer: an upload cut
  off by a reset is not taken for part of the next one.
- The NAOMI per-game table is matched on the whole name: a name that
  was part of another entry's (an empty one: Samurai Spirits 6's) got
  that entry's settings.
- NaomiNetwork::receive waits for both bytes of the packet number, and
  does not report a half-received packet as received when stopping.
2026-10-13 12:26:55 +02:00
LibretroAdmin 3015196cc6 maple: a device change through a state load, the bus from the descriptor
- A state saved before the frontend changed a Dreamcast port's device
  and loaded after (run-ahead does this every frame) brought back the
  old devices with nothing to put the new ones in: the change was lost.
  After a load, what is not as the settings say is unplugged and the
  right devices plugged in a tenth of a second later, as for a live
  change - the same for the same state and settings every time.
- The bus a frame goes out on comes from the DMA descriptor, not from
  the frame's address, and a device without expansion slots answers the
  frames addressed to its slots (upstream a429fba21, MAME agrees). A
  device answers with its own bus's attached-device bits.
- The VMU screen after a load: a controller's second card, never drawn
  on, no longer puts its blank screen over the first card's picture.
2026-10-13 12:26:51 +02:00
LibretroAdmin 087cc0c49c maple, mem: only changed devices unplugged, VMU clock, gun flag, fallback memory
- When the frontend changes a port's device, a Dreamcast unplugs only
  what changes (the bus whose device changes, a slot whose device or
  card file changes) and plugs in the rest a tenth of a second later.
  Everything was unplugged: a memory-card write in that window was lost
  (the threaded/non-threaded state comparison in live.sh failed on it).
- The VMU clock reads the console's RTC, which is in a save state, not
  the host's clock: a frame run again from a state got another date.
- A later light-gun occupy request for a bus with no gun no longer
  clears the flag a gun had set.
- Without the fast-memory layout: each memory has a zeroed spare page
  (unaligned accesses at the end went past the heap block); Windows frees
  _aligned_malloc memory with _aligned_free; video memory fault offsets
  drop the Android ARM64 pointer tag.
2026-10-13 11:08:16 +02:00
LibretroAdmin 3405e306ca maple: coins, encoders and reconnection in a state; a 32-bit build's states in a 64-bit one
The I/O boards' coin counters were not in a state: a load made the
boards anew with nothing counted, and the game, which goes by how far a
count has moved since it last looked, saw coins come or go - on every
frame with run-ahead. They are in maple_serialize_v21(), with the coin
switches (a coin held across a load was otherwise counted twice), Wave
Runner GP's drive board byte, the rotary encoders' positions, and the
time at which unplugged devices are plugged in again: without that, a
change of device under run-ahead left every port empty from then on.
84 bytes, whatever the machine has.

How many boards there are was written as a size_t: eight bytes by a
64-bit build and four by a 32-bit one, and each took the other's state
for its own, with everything after it read four bytes out. What is
written is unchanged; the reader tells the two apart (the four bytes
more are zeroes, and what follows a 32-bit count never starts with four
of them).

Devices that came back after the wait replaced the ones a state loaded
in the meantime had put there without taking those away first.
2026-10-10 23:23:25 +02:00
LibretroAdmin ca211ee386 maple: frames are as long as their headers say; JVS and firmware bounds
A Maple frame was read by what each device expected to find in it. A VMU
block write with a short frame made the count wrap and copied some 4 GB
into the card's memory. A word is now read only when the frame has one
left; the VMU's screen and the rumble pack act only on a frame that is
all there.

The table of frames and each frame have to lie in RAM, and an answer goes
to RAM, all of it: the addresses are the game's, or a state's. What a
device is given is no longer than the table says the frame is.

JVS: lengths, channel numbers and counts in the cabinet's messages are
held to the frame and to the reply (255 bytes); the encoder count to the
eight there are; a request kept for later is dropped if it and the new
one do not fit. The I/O board's firmware upload is cut at the end of its
64 KB. From a state: no more boards than the cabinet has, and a pending
answer length that cannot be one is none.
2026-10-10 20:09:19 +02:00
LibretroAdmin 04d93f31cd sh4_sched: an event registered again keeps its place; resets drop their own events
The scheduler's list is the process's and outlives the machine. Nothing
is ever taken out of it, so each game loaded after the first added up to
ten entries of its own, and an event the old machine had asked for - the
old scanline event asked for itself again each time - went on coming to
the new one. A callback that is already in the list now gets the place it
has, with nothing waiting in it. Ids no longer change from one load to
the next; states name the events by variable, so nothing in them moves.

A reset left events of the machine before it waiting: the next piece of a
GD-ROM transfer, the end of a Maple, AICA or NAOMI 2 transfer, a render's
end, a modem step. Each came after the reset and raised its interrupt for
a transfer the registers no longer knew about. Each device's reset now
takes back its own, where it clears what the event works on. There is no
central clear and the clock is not restarted.

The sound chip's sample tick and the clock's second are not the machine's
to lose: they are asked for by the first reset, which is when they were
asked for before, and left alone by every later one.

A soft reset leaves an AICA transfer's end to come (SB_ADST stays set and
the event is what ends it), and the NAOMI 2's, whose chip it does not
reset.

sh4_sched_is_scheduled() answers no for an id that was never given out.
2026-10-10 20:08:26 +02:00
LibretroAdmin c308deb2c2 maple: a device's answer arrives when the transfer is over, and takes as long as it does
Read against upstream's, which changed all of this for games:

- The answers were written into the game's memory the moment a
  transfer was started, and the interrupt came later. A game that
  looks before the interrupt found them there already. They are now
  kept until the transfer is over and written then, with the
  interrupt. (Upstream: "Maple dma xfer must not be executed
  immediately. Delay until interrupt is raised.")

- An answer with nowhere to go, its address not in main memory, was
  written to some other address made out of it. It is now not
  written, and the overrun interrupt is raised when the transfer is
  over. (Upstream: fixes Cheats 'N Codes Volume 1.)

- The time a transfer takes was every byte at 2 Mbit/s. Only the
  console sends that fast: devices answer at 724 to 738 kbit/s,
  measured on the wire, and each frame has its start, parity and stop
  as well. Now 2 Mbit/s out and 740 kbit/s back, as upstream has it.
  (Upstream: fixes Silent Scope's memory card load at boot. Its commit
  also notes that Power Drift then only boots with one controller
  connected; that is not looked into here.)

- In the mode where the bus sends the most significant byte first
  (SB_MMSEL 0), the last word of a frame was not byte-swapped on its
  way to the device.

The pending answers are in the save state, which becomes V18 and
16 KB larger; older states load as before. They are dropped on reset.

The disc gains a test: a controller's answer must not be in memory
right after the transfer is started and must be when it is over. With
answers written at once it fails (bad00901).
2026-10-07 12:12:06 +02:00
LibretroAdmin f9f970c113 maple: VMU and EEPROM writes leave the emulation path
A VMU block write and a JVS EEPROM write only update the device's
memory and mark it dirty; maple_FlushSaves() writes the dirty span out
once per frame from retro_run, while the machine is asleep, and the
device destructors flush what is left. A save that used to cost a
seek, a write and an fflush per 128-byte phase on the emulation thread
is one write of its span per frame instead.
2026-10-06 12:34:24 +02:00
twinaphex 8fa6f79bcb Backport most of this commit - https://github.com/flyinghead/flycast/commit/ef16842074560bd0b8febcc006d31f57ae7c2914#diff-cd8013797851ba94cbf725dbb44a0cf68816b3277b36309bef4dceb39ff7272f 2021-03-05 23:22:56 +01:00
barbudreadmon fa49de2997 (SH4) backport https://github.com/flyinghead/flycast/commit/333df13fce8a0bc577d6397c384abf86ea5daf24
(SH4) backport https://github.com/flyinghead/flycast/commit/a19c73de7b79b6c504798768a32922994f52c57f
sync soft/hard reset calls with upstream
2020-12-24 13:34:48 +01:00
barbudreadmon b6bac7c9c5 Backport https://github.com/flyinghead/flycast/commit/a446199312e7b9e29237ad597399b1b2ac084381 2020-11-26 08:56:27 +01:00
barbudreadmon a73e235536 Backport https://github.com/flyinghead/flycast/commit/6402c8e7ed0d71ecd636e4812f8faeb3b6de66ed 2020-11-26 08:25:57 +01:00
barbudreadmon aba25cd17e (Maple) Backport https://github.com/flyinghead/flycast/commit/8192eea387467b3aece1fa2aeccc75d320191749 properly 2020-11-18 18:53:41 +01:00
barbudreadmon 155ff88dc6 Revert "(Maple) Backport https://github.com/flyinghead/flycast/commit/8192eea387467b3aece1fa2aeccc75d320191749#diff-cd8013797851ba94cbf725dbb44a0cf68816b3277b36309bef4dceb39ff7272f"
This reverts commit e6dd855a05.
2020-11-18 18:12:51 +01:00
barbudreadmon b05f3bf089 Revert "(Maple) Backport https://github.com/flyinghead/flycast/commit/6402c8e7ed0d71ecd636e4812f8faeb3b6de66ed#diff-3a66da53e6f4789ea79313619e0f4fa0eaa7ea2d113f1def537c4961debe6161"
This reverts commit 756846b6a7.
2020-11-18 18:12:51 +01:00
barbudreadmon 4bb0f82c83 Revert "(AICA/MAPLE) Backport https://github.com/flyinghead/flycast/commit/a446199312e7b9e29237ad597399b1b2ac084381#diff-3a66da53e6f4789ea79313619e0f4fa0eaa7ea2d113f1def537c4961debe6161"
This reverts commit ef975de635.
2020-11-18 18:12:50 +01:00
twinaphex ef975de635 (AICA/MAPLE) Backport https://github.com/flyinghead/flycast/commit/a446199312e7b9e29237ad597399b1b2ac084381#diff-3a66da53e6f4789ea79313619e0f4fa0eaa7ea2d113f1def537c4961debe6161 2020-11-15 19:27:34 +01:00
twinaphex 756846b6a7 (Maple) Backport https://github.com/flyinghead/flycast/commit/6402c8e7ed0d71ecd636e4812f8faeb3b6de66ed#diff-3a66da53e6f4789ea79313619e0f4fa0eaa7ea2d113f1def537c4961debe6161 2020-11-15 19:08:58 +01:00
twinaphex e6dd855a05 (Maple) Backport https://github.com/flyinghead/flycast/commit/8192eea387467b3aece1fa2aeccc75d320191749#diff-cd8013797851ba94cbf725dbb44a0cf68816b3277b36309bef4dceb39ff7272f 2020-11-15 19:04:00 +01:00
twinaphex e9dd27e97b Backport partial changes here https://github.com/flyinghead/flycast/commit/6402c8e7ed0d71ecd636e4812f8faeb3b6de66ed 2020-10-10 23:05:03 +02:00
Flyinghead 6544c9f32d support multi-session cue/bin. mipmap D-adjust only to increase LoD
limit maple schedule time
allow vram 8-bit reads
gl: use common ReadFramebuffer() func
other minor changes
2020-03-28 14:25:52 +01:00
Flyinghead 8e7250fc6c proper hard reset of sh4 mm registers
clean up
2019-09-04 09:49:04 +02:00
Flyinghead 58ac148f07 minor changes and clean up 2019-08-31 16:10:52 +02:00
Flyinghead 058db561ce more logging 2019-08-30 13:11:18 +02:00
Flyinghead 8452fb11a2 wince: basic mmu, interpreter support, fpu disable exceptions 2019-05-01 19:35:26 +02:00
Flyinghead 1a9579a351 maple: reconnect devices after 100ms to allow the game to detect it
Purupuru option doesn't require restart anymore
2019-04-05 14:31:52 +02:00
Flyinghead db17fcb6cc Naomi: fixes for vathlete, csmash, hotd and more
Load default eeprom from mame rom if present
Fix controls for hotd2 and alpilot
Fix vathlete graphical gltches due to huge negative z values
GD-rom games now have proper game id
Fix csmash crash entering game test mode
2018-11-20 12:59:18 +01:00
Flyinghead f0676bd1ad JVS: fix substract coin, array overflow and more 2018-10-21 14:59:10 +02:00
Flyinghead e26418b8a7 Naomi: better JVS emulation 2018-10-12 01:45:40 +02:00
Flyinghead 9e28371e42 Light Gun support 2018-10-02 09:51:30 +02:00
twinaphex bf762e8be7 Updated/rebased 2018-06-15 06:34:34 +02:00
twinaphex d8f9053d07 Split up/rebase holly files 2018-06-15 06:17:17 +02:00
twinaphex 7659bd0f99 Combine holly files into one 2017-05-12 08:21:29 +02:00
twinaphex 4f10b21c2d (core/hw/maple) Cleanups 2016-10-17 02:46:00 +02:00
twinaphex 02a7c8fa2e Turn some functions static 2016-10-13 00:48:42 +02:00
twinaphex e3fdd64c39 rename 'schid' to 'sched' 2015-12-27 09:28:30 +01:00
twinaphex 2fa562db1b Start creating asic_RaiseInterruptWait 2015-12-27 08:46:39 +01:00
twinaphex 55d4fb8f21 Get rid of config code 2015-12-18 07:08:40 +01:00
Stefanos Kornilios Mitsis Poiitidis f5d29677b3 Merge branch 'androidui'
Conflicts:
	core/hw/pvr/spg.cpp
	core/hw/sh4/interpr/sh4_interpreter.cpp
	reicast/android/src/com/reicast/emulator/MainActivity.java
2013-12-28 22:28:50 +01:00
Stefanos Kornilios Mitsis Poiitidis 7ef9de3cae Moving code around, cleanups 2013-12-28 22:20:08 +01:00