Journal de portage · 29 août 2026

Portage SFEX2P

Street Fighter EX2 Plus remis à plat sur la dernière psxrecomp — un scaffold propre, trois bugs runtime, trois correctifs.

Jeu SLUS-01105 · entry 0x801CA7D8 Framework psxrecomp v0.3.2-alpha BIOS SCPH-1001 US (LLE)

RÉSUMÉ

Où on en est

Le build est jouable de bout en bout : boot, combat, et — pour la première fois dans ce projet — le retour au Mode Select après un Reset.

✓ Boot ✓ Gameplay 60 Hz ✓ Manette DualSense ✓ Retour Mode Select

Trois bugs traités : une régression de boot (un correctif d'atelier jamais remonté en amont), une manette morte en jeu (mauvais mode de pad), et l'écran noir au Reset — un bug framework de longue date, cette fois tracé en direct et corrigé.

01

Mise à jour de psxrecomp

Le checkout partagé psxrecomp/ est passé de a7c1fac (v0.3.1-alpha-625) à 00438851 — le tag v0.3.2-alpha, environ 170 commits plus loin.

Les modifications locales non commitées (hooks du serveur debug Beetle, un correctif de setup_project.ps1) ont été mises de côté proprement : git stash + branche backup-pre-v032-bump-2026-08-29. Rien n'est perdu.

02

Deux bugs du scaffold Windows

setup_project.ps1 ne parse plus sous PowerShell 5.1

La version v0.3.2 du script contient trois Write-Warning avec un tiret cadratin —. Le fichier est en UTF-8 sans BOM ; PowerShell 5.1 le lit en ANSI, les octets mal décodés cassent le parseur en cascade. Second défaut : l'appel à probe_disc.py passe encore --description $Description en positionnel, donc un flag optionnel vide décale tous les arguments suivants.

Corrigés à la main : ponctuation non-ASCII remplacée, arguments construits dans un tableau et ajoutés seulement s'ils sont fournis.

Le bug BOM historique, toujours là

Les substitutions --set-file injectent des marqueurs BOM (U+FEFF) en plein milieu des fichiers générés : 6 occurrences dans CMakeLists.txt et symbols.toml, retirées avant le premier cmake.

03

Scaffold et pipeline SFEX2P

Nouveau dossier SFEX2P (nom d'affichage « Street Fighter EX2 Plus » conservé), 2 joueurs, recomp-ui + wizard + CI, netplay désactivé. Sondage disque : SLUS-01105, boot SLUS_011.05, entry 0x801CA7D8, 995 seeds.

ÉtapeRésultat
build_emitters.shémetteurs prêts sous build-recompiler/
generate51 shards · 1 912 806 lignes de C · table de dispatch 2079 entrées
cmake + ninjacompile sans erreur

Piège : avertissement « BIOS generated/ is STALE ». Faux positif — le chemin psxrecomp_cli.py generate ne dépose pas l'empreinte OpenBIOS.emitter.sha comme le fait regen_bios.sh. Empreinte écrite à la main.

04

Réglages game.toml

CléValeurRaison
[video] vsync"off"Sur moniteur 120 Hz, laisser le vsync piloter la cadence fait tourner le jeu à 2×. Force le pacer horloge à 59,94 Hz.
[runtime] overlay_cachefalseAligné sur le projet sœur Plus Alpha.
[controller] multitap_analogfalseMultitap activé par erreur au scaffold (voir bug #2).
bios_hle / openbiosfalse / falseBascule sur BIOS retail SCPH-1001 (voir bug #3).

05 · BUG CORRIGÉ

Freeze au boot — régression du registre SR

Premier lancement sur v0.3.2 stock : gel à la frame 1505, écran noir, quatre freeze_dump, cop0_sr = 0x40000400, iec = 0, epc = 0x801303E8.

C'est exactement le bug SR/TCB que l'atelier avait corrigé le 24 août 2026. Ce correctif n'a jamais été remonté chez mstan/psxrecomp : la v0.3.2 refait un double transformé (push/pop logiciel) du SR aux trois sites de traps.c. Ré-appliqué la copie brute :

// psx_save_context_to_tcb / psx_restore_context_from_tcb
- cpu->write_word(save + 140u, (sr & ~0x3Fu) | ((sr & 0x0Fu) << 2));
+ cpu->write_word(save + 140u, sr);            // copie brute, comme le BIOS retail

Après : tourne au-delà de la frame 9400, iec = 1, sr = 0x40000401, zéro freeze_dump. Commit sous-module 09ff2311.

06 · BUG CORRIGÉ

Manette morte en jeu

La DualSense (USB) est bien détectée — opened controller for slot: DualSense Wireless Controller — mais zéro entrée pendant un combat. Le launcher, lui, la voit parfaitement (couche SDL).

Cause : le launcher avait écrit settings.toml [controller] p1_mode = "analog" et multitap = true. Street Fighter EX2 Plus est un jeu à pad digital uniquement — en mode analog / DualShock il ne reconnaît pas la manette et ignore tout en jeu.

Correctif : p1_mode = "digital", multitap = false, multitap_analog = false. Si le launcher réécrit le fichier, choisir explicitement le mode Digital et couper le multitap dans son interface avant de lancer.

07 · BUG CORRIGÉ

Retour Mode Select → écran noir

Le bug de fond : après un Reset en jeu, au lieu du « Now Loading » puis du menu, écran noir permanent. Documenté depuis plusieurs sessions, jamais résolu.

La piste Plus Alpha

Le dépôt guimaraf/plusalpha-recomp (Street Fighter EX Plus Alpha, jeu sœur du même studio Arika) utilise un fork de psxrecomp. Ce fork n'a aucun correctif CD/thread/interruptions. Son seul vrai levier : le BIOS retail SCPH-1001 au lieu d'OpenBIOS.

Bascule sur BIOS retail

  • Tentée d'abord avec un dump SCPH-7502 EU → le C généré du BIOS ne compile pas (goto vers un label non émis ; 651 fonctions ignorées ; le recompiler attend une image US).
  • Avec un vrai SCPH-1001 US (crc32 37157331) → compile proprement (1 fonction ignorée). Bannière image=SCPH-1001.
  • Résultat : le BIOS retail ne corrige pas le Reset. Signature de gel identique — epc = 0x8013038C, sr = 0x40000404, iec = 0. Bug du runtime psxrecomp, pas du BIOS.

08

Investigation live (serveur debug)

Build build-debugtools (serveur debug port 4370). L'utilisateur pilote le jeu jusqu'au Reset ; interrogation de l'état gelé.

CommandeCe qu'elle montre
freeze_checkcop0_epc=0x8013038C, cop0_sr=0x40000404, iec=0, in_exception=0, tout en interpréteur dirty-RAM
cdrom_stateirq_flag=0x03 (INT3 jamais acquitté) · pending cmd=0x09 (Pause) bloquée active
dispatch_tailboucle 0x445C · 0x5000 · 0x1C5C · 0x2104 — code BIOS en RAM, aucun code jeu
thread_ctx_ring3 threads coopératifs : main 0xA000E29C, CD 0xA000E35C, Reset 0xA000E41C
irqctx_ringfigé depuis la frame 3883 — plus aucune interruption livrée
read_ram 0xA000E3F0case SR du TCB du thread CD = 0x40000404 confirmé en RAM

La transition fautive

À la frame 3897 : le thread main est sauvé avec sr=0x40000401 (IEc=1, sain), puis le thread CD est restauré avec resume_pc=0x80130508 et sr=0x40000404. À partir de là, chaque save/restore du thread CD porte 0x40000404. Puis plus jamais de changement de thread.

Le mécanisme

  • Une interruption VBLANK frappe le thread CD à 0x8013038C. Le matériel empile le SR : 0x40000401 → 0x40000404 (l'ancien IEc va dans IEp, le nouvel IEc passe à 0).
  • Le noyau sauve le thread CD dans son TCB avec ce SR empilé.
  • Au restore, la « copie brute » (correctif du bug #1) fait cop0_sr = 0x40000404 → IEc reste à 0 pour toujours. Aucun rfe ne dépile jamais.
  • IEc=0 → l'ACK CD-ROM (INT3) n'est jamais servi → process_pending() bloque la commande Pause → faux « CD timeout » → écran noir, round-robin des threads figé.

09 · CORRECTIF

Le pop conditionnel

La contradiction

Le fix boot a besoin d'une copie brute : la case SR d'un thread fraîchement ouvert vaut 0x40000401, jamais empilé — un pop perdrait IEc.

Le fix Reset a besoin du pop : la case vaut 0x40000404, empilé par le matériel — sans pop, IEc reste à 0.

Les deux passent par le même psx_restore_context_from_tcb. Discriminant : le bit IEc du SR sauvé.

uint32_t saved_sr = cpu->read_word(save + 140u);
if (saved_sr & 0x01u) {
    // IEc armé : thread garé proprement (yield coopératif / thread neuf)
    cpu->cop0[12] = saved_sr;                                // copie brute
} else {
    // IEc à 0 : suspendu EN PLEINE EXCEPTION. Le restore du scheduler HLE
    // tient lieu du ReturnFromException du noyau, dont le rfe final dépile.
    cpu->cop0[12] = (saved_sr & 0xFFFFFFC0u) | ((saved_sr >> 2) & 0x0Fu);
}

pop(0x40000404) = 0x40000401. Même règle appliquée au fallback ReturnFromException de syscall(3).

Vérifié — en direct sur le serveur debug et par l'utilisateur : le menu revient après le Reset, le compteur de frames dépasse 26 000, wedge: None, zéro freeze_dump. Commit sous-module 36e124d3.

RÉCAP

Commits

SHADépôtContenu
67ba7e8SFEX2PScaffold New Project Layout
8630f88SFEX2PStrip BOM · vsync=off (fix 120 Hz)
09ff2311psxrecompfix SR copie brute (ré-application atelier 24 août)
7b2f0acSFEX2PBump sous-module — fix boot
412ec99SFEX2PPad digital · multitap off · overlay_cache=false
433743dSFEX2PBIOS retail SCPH-1001 US
36e124d3psxrecompfix pop rfe du SR au restore si IEc=0
928b287SFEX2PBump sous-module — fix retour Mode Select

À RETENIR

Deux bugs framework à remonter en amont

Les deux correctifs SR (09ff2311 et 36e124d3) vivent dans le carve-out du scheduler coopératif TCB de traps.c — du code que tous les projets de recomp partagent. Aucun n'est chez mstan/psxrecomp upstream.

Consigne

À chaque bump de psxrecomp sur le master amont, ré-appliquer les deux correctifs. Ils méritent une PR upstream : le pop conditionnel est fidèle au matériel (le rfe dépile la pile IEc/KUc) et satisfait les deux cas avec preuve live.

Le BIOS retail SCPH-1001 n'est pas requis par ce correctif — conservé car plus fidèle qu'OpenBIOS.

SFEX2P · psxrecomp v0.3.2-alpha-32-g36e124d3 · recomp-ui 2b7e9c6 · 29 août 2026

Port log · 29 August 2026

SFEX2P Port

Street Fighter EX2 Plus rebuilt on the latest psxrecomp — a clean scaffold, three runtime bugs, three fixes.

Game SLUS-01105 · entry 0x801CA7D8 Framework psxrecomp v0.3.2-alpha BIOS SCPH-1001 US (LLE)

SUMMARY

Where things stand

The build is playable end to end : boot, matches, and — for the first time in this project — the return to Mode Select after an in-game Reset.

✓ Boot ✓ 60 Hz gameplay ✓ DualSense controller ✓ Return to Mode Select

Three bugs handled : a boot regression (a workshop fix never sent upstream), a dead controller in-game (wrong pad mode), and the black screen on Reset — a long-standing framework bug, this time traced live and fixed.

01

Updating psxrecomp

The shared psxrecomp/ checkout went from a7c1fac (v0.3.1-alpha-625) to 00438851 — the v0.3.2-alpha tag, about 170 commits further on.

Uncommitted local changes (Beetle debug-server hooks, a setup_project.ps1 fix) were stashed cleanly : git stash + a backup-pre-v032-bump-2026-08-29 branch. Nothing lost.

02

Two Windows scaffold bugs

setup_project.ps1 no longer parses under PowerShell 5.1

The v0.3.2 script has three Write-Warning lines containing an em dash —. The file is UTF-8 with no BOM ; PowerShell 5.1 reads it as ANSI, and the mis-decoded bytes cascade into dozens of bogus parser errors. Second flaw : the probe_disc.py call still passes --description $Description positionally, so an empty optional flag shifts every following argument.

Fixed by hand : non-ASCII punctuation replaced, arguments built as an array and appended only when set.

The old BOM bug, still there

The --set-file substitutions inject BOM markers (U+FEFF) mid-file : 6 occurrences in CMakeLists.txt and symbols.toml, stripped before the first cmake.

03

SFEX2P scaffold and pipeline

New SFEX2P folder (display name "Street Fighter EX2 Plus" kept), 2 players, recomp-ui + wizard + CI, netplay off. Disc probe : SLUS-01105, boot SLUS_011.05, entry 0x801CA7D8, 995 seeds.

StepResult
build_emitters.shemitters ready under build-recompiler/
generate51 shards · 1,912,806 lines of C · dispatch table 2079 entries
cmake + ninjacompiles clean

Gotcha : a "BIOS generated/ is STALE" warning. False positive — the psxrecomp_cli.py generate path doesn't drop the OpenBIOS.emitter.sha fingerprint the way regen_bios.sh does. Fingerprint written by hand.

04

game.toml settings

KeyValueReason
[video] vsync"off"On a 120 Hz monitor, letting vsync drive cadence runs the game at 2×. Forces the 59.94 Hz wall-clock pacer.
[runtime] overlay_cachefalseAligned with the sibling Plus Alpha project.
[controller] multitap_analogfalseMultitap enabled by mistake at scaffold (see bug #2).
bios_hle / openbiosfalse / falseSwitch to the retail SCPH-1001 BIOS (see bug #3).

05 · BUG FIXED

Boot freeze — SR register regression

First launch on stock v0.3.2 : freeze at frame 1505, black screen, four freeze_dumps, cop0_sr = 0x40000400, iec = 0, epc = 0x801303E8.

This is exactly the SR/TCB bug the workshop fixed on 24 August 2026. That fix was never sent upstream to mstan/psxrecomp : v0.3.2 still does a software push/pop double-transform of the SR at the three sites in traps.c. Raw copy re-applied :

// psx_save_context_to_tcb / psx_restore_context_from_tcb
- cpu->write_word(save + 140u, (sr & ~0x3Fu) | ((sr & 0x0Fu) << 2));
+ cpu->write_word(save + 140u, sr);            // raw copy, like the retail BIOS

After : runs past frame 9400, iec = 1, sr = 0x40000401, zero freeze_dump. Submodule commit 09ff2311.

06 · BUG FIXED

Dead controller in-game

The DualSense (USB) is detected fine — opened controller for slot: DualSense Wireless Controller — but zero input during a match. The launcher sees it perfectly (SDL layer).

Cause : the launcher had written settings.toml [controller] p1_mode = "analog" and multitap = true. Street Fighter EX2 Plus is a digital-pad-only game — in analog / DualShock mode it doesn't recognise the controller and ignores all input in-game.

Fix : p1_mode = "digital", multitap = false, multitap_analog = false. If the launcher rewrites the file, explicitly pick Digital mode and turn multitap off in its UI before launching.

07 · BUG FIXED

Return to Mode Select → black screen

The core bug : after an in-game Reset, instead of "Now Loading" then the menu, a permanent black screen. Documented across several sessions, never resolved.

The Plus Alpha lead

The repo guimaraf/plusalpha-recomp (Street Fighter EX Plus Alpha, a sibling game from the same Arika studio) uses a psxrecomp fork. That fork has no CD/thread/interrupt fix. Its one real lever : the retail SCPH-1001 BIOS instead of OpenBIOS.

Switching to the retail BIOS

  • First tried with a SCPH-7502 EU dump → the generated BIOS C fails to compile (goto to an un-emitted label ; 651 skipped functions ; the recompiler expects a US image).
  • With a genuine SCPH-1001 US (crc32 37157331) → compiles clean (1 skipped function). Banner image=SCPH-1001.
  • Result : the retail BIOS does not fix the Reset. Freeze signature identical — epc = 0x8013038C, sr = 0x40000404, iec = 0. A psxrecomp runtime bug, not the BIOS.

08

Live investigation (debug server)

build-debugtools build (debug server on port 4370). The user drives the game to the Reset ; the frozen state is then queried.

CommandWhat it shows
freeze_checkcop0_epc=0x8013038C, cop0_sr=0x40000404, iec=0, in_exception=0, all in the dirty-RAM interpreter
cdrom_stateirq_flag=0x03 (INT3 never acknowledged) · pending cmd=0x09 (Pause) stuck active
dispatch_tailloop 0x445C · 0x5000 · 0x1C5C · 0x2104 — BIOS code in RAM, no game code
thread_ctx_ring3 cooperative threads : main 0xA000E29C, CD 0xA000E35C, Reset 0xA000E41C
irqctx_ringfrozen since frame 3883 — no interrupt delivered since
read_ram 0xA000E3F0SR slot of the CD thread's TCB = 0x40000404 confirmed in RAM

The faulty transition

At frame 3897 : the main thread is saved with sr=0x40000401 (IEc=1, healthy), then the CD thread is restored with resume_pc=0x80130508 and sr=0x40000404. From then on, every save/restore of the CD thread carries 0x40000404. Then no thread switch ever again.

The mechanism

  • A VBLANK interrupt hits the CD thread at 0x8013038C. Hardware pushes the SR : 0x40000401 → 0x40000404 (old IEc into IEp, new IEc becomes 0).
  • The kernel saves the CD thread into its TCB with that pushed SR.
  • On restore, the "raw copy" (bug #1's fix) makes cop0_sr = 0x40000404 → IEc stays 0 forever. No rfe ever pops it.
  • IEc=0 → the CD-ROM ACK (INT3) is never serviced → process_pending() blocks the Pause command → false "CD timeout" → black screen, thread round-robin frozen.

09 · FIX

The conditional pop

The contradiction

The boot fix needs a raw copy : a freshly opened thread's SR slot holds 0x40000401, never pushed — a pop would drop IEc.

The Reset fix needs the pop : the slot holds 0x40000404, pushed by hardware — without the pop, IEc stays 0.

Both go through the same psx_restore_context_from_tcb. Discriminator : the IEc bit of the saved SR.

uint32_t saved_sr = cpu->read_word(save + 140u);
if (saved_sr & 0x01u) {
    // IEc set: thread parked cleanly (cooperative yield / fresh thread)
    cpu->cop0[12] = saved_sr;                                // raw copy
} else {
    // IEc clear: suspended MID-EXCEPTION. The HLE scheduler restore stands
    // in for the kernel ReturnFromException, whose final rfe pops the stack.
    cpu->cop0[12] = (saved_sr & 0xFFFFFFC0u) | ((saved_sr >> 2) & 0x0Fu);
}

pop(0x40000404) = 0x40000401. The same rule applies to the syscall(3) ReturnFromException fallback.

Verified — live on the debug server and by the user : the menu returns after the Reset, the frame counter passes 26,000, wedge: None, zero freeze_dump. Submodule commit 36e124d3.

RECAP

Commits

SHARepoWhat
67ba7e8SFEX2PNew Project Layout scaffold
8630f88SFEX2PStrip BOM · vsync=off (120 Hz fix)
09ff2311psxrecompfix raw SR copy (re-apply 24 Aug workshop)
7b2f0acSFEX2PSubmodule bump — boot fix
412ec99SFEX2PDigital pad · multitap off · overlay_cache=false
433743dSFEX2PRetail SCPH-1001 US BIOS
36e124d3psxrecompfix rfe pop of SR on restore when IEc=0
928b287SFEX2PSubmodule bump — Mode Select fix

TAKEAWAY

Two framework bugs to send upstream

Both SR fixes (09ff2311 and 36e124d3) live in the cooperative TCB scheduler carve-out in traps.c — code every recomp project shares. Neither is in mstan/psxrecomp upstream.

Standing note

On every psxrecomp bump against upstream master, re-apply both fixes. They deserve an upstream PR : the conditional pop is faithful to hardware (the rfe pops the IEc/KUc stack) and satisfies both cases with live evidence.

The retail SCPH-1001 BIOS is not required by this fix — kept because it's more faithful than OpenBIOS.

SFEX2P · psxrecomp v0.3.2-alpha-32-g36e124d3 · recomp-ui 2b7e9c6 · 29 August 2026

Diário do port · 29 de agosto de 2026

Port SFEX2P

Street Fighter EX2 Plus refeito sobre a psxrecomp mais recente — um scaffold limpo, três bugs de runtime, três correções.

Jogo SLUS-01105 · entry 0x801CA7D8 Framework psxrecomp v0.3.2-alpha BIOS SCPH-1001 US (LLE)

RESUMO

Situação atual

O build é jogável de ponta a ponta : boot, partidas, e — pela primeira vez neste projeto — a volta ao Mode Select depois de um Reset no jogo.

✓ Boot ✓ Gameplay 60 Hz ✓ Controle DualSense ✓ Volta ao Mode Select

Três bugs tratados : uma regressão de boot (uma correção de bancada nunca enviada ao upstream), um controle morto no jogo (modo de pad errado) e a tela preta no Reset — um bug de framework antigo, desta vez rastreado ao vivo e corrigido.

01

Atualização da psxrecomp

O checkout compartilhado psxrecomp/ passou de a7c1fac (v0.3.1-alpha-625) para 00438851 — a tag v0.3.2-alpha, cerca de 170 commits à frente.

As mudanças locais não commitadas (hooks do servidor de debug do Beetle, uma correção do setup_project.ps1) foram guardadas com segurança : git stash + branch backup-pre-v032-bump-2026-08-29. Nada perdido.

02

Dois bugs do scaffold no Windows

setup_project.ps1 não é mais interpretado no PowerShell 5.1

A versão v0.3.2 do script tem três Write-Warning com um travessão —. O arquivo é UTF-8 sem BOM ; o PowerShell 5.1 o lê como ANSI, e os bytes mal decodificados quebram o parser em cascata. Segundo defeito : a chamada ao probe_disc.py ainda passa --description $Description por posição, então um flag opcional vazio desloca todos os argumentos seguintes.

Corrigidos à mão : pontuação não-ASCII substituída, argumentos montados como array e adicionados só quando definidos.

O antigo bug de BOM, ainda presente

As substituições --set-file injetam marcadores BOM (U+FEFF) no meio dos arquivos gerados : 6 ocorrências em CMakeLists.txt e symbols.toml, removidas antes do primeiro cmake.

03

Scaffold e pipeline SFEX2P

Nova pasta SFEX2P (nome de exibição "Street Fighter EX2 Plus" mantido), 2 jogadores, recomp-ui + wizard + CI, netplay desativado. Sondagem do disco : SLUS-01105, boot SLUS_011.05, entry 0x801CA7D8, 995 seeds.

EtapaResultado
build_emitters.shemitters prontos em build-recompiler/
generate51 shards · 1.912.806 linhas de C · tabela de dispatch com 2079 entradas
cmake + ninjacompila sem erros

Pegadinha : aviso "BIOS generated/ is STALE". Falso positivo — o caminho psxrecomp_cli.py generate não grava a impressão digital OpenBIOS.emitter.sha como o regen_bios.sh faz. Impressão digital escrita à mão.

04

Ajustes no game.toml

ChaveValorMotivo
[video] vsync"off"Em monitor de 120 Hz, deixar o vsync ditar a cadência roda o jogo a 2×. Força o pacer de relógio de 59,94 Hz.
[runtime] overlay_cachefalseAlinhado ao projeto irmão Plus Alpha.
[controller] multitap_analogfalseMultitap ativado por engano no scaffold (ver bug #2).
bios_hle / openbiosfalse / falseTroca para o BIOS retail SCPH-1001 (ver bug #3).

05 · BUG CORRIGIDO

Congelamento no boot — regressão do registrador SR

Primeiro lançamento na v0.3.2 pura : congela no frame 1505, tela preta, quatro freeze_dump, cop0_sr = 0x40000400, iec = 0, epc = 0x801303E8.

É exatamente o bug de SR/TCB que a bancada corrigiu em 24 de agosto de 2026. Essa correção nunca foi enviada ao upstream do mstan/psxrecomp : a v0.3.2 ainda faz um duplo transform (push/pop por software) do SR nos três pontos de traps.c. Cópia bruta reaplicada :

// psx_save_context_to_tcb / psx_restore_context_from_tcb
- cpu->write_word(save + 140u, (sr & ~0x3Fu) | ((sr & 0x0Fu) << 2));
+ cpu->write_word(save + 140u, sr);            // cópia bruta, como o BIOS retail

Depois : roda além do frame 9400, iec = 1, sr = 0x40000401, zero freeze_dump. Commit no submódulo 09ff2311.

06 · BUG CORRIGIDO

Controle morto no jogo

O DualSense (USB) é detectado normalmente — opened controller for slot: DualSense Wireless Controller — mas nenhuma entrada durante uma partida. O launcher o enxerga perfeitamente (camada SDL).

Causa : o launcher havia gravado settings.toml [controller] p1_mode = "analog" e multitap = true. Street Fighter EX2 Plus é um jogo somente de pad digital — em modo analógico / DualShock ele não reconhece o controle e ignora toda entrada no jogo.

Correção : p1_mode = "digital", multitap = false, multitap_analog = false. Se o launcher reescrever o arquivo, escolha explicitamente o modo Digital e desligue o multitap na interface dele antes de iniciar.

07 · BUG CORRIGIDO

Volta ao Mode Select → tela preta

O bug central : depois de um Reset no jogo, em vez de "Now Loading" e o menu, uma tela preta permanente. Documentado em várias sessões, nunca resolvido.

A pista do Plus Alpha

O repositório guimaraf/plusalpha-recomp (Street Fighter EX Plus Alpha, jogo irmão do mesmo estúdio Arika) usa um fork da psxrecomp. Esse fork não tem correção de CD/thread/interrupções. Sua única alavanca real : o BIOS retail SCPH-1001 em vez do OpenBIOS.

Troca para o BIOS retail

  • Primeiro tentado com um dump SCPH-7502 EU → o C gerado do BIOS não compila (goto para um label não emitido ; 651 funções ignoradas ; o recompiler espera uma imagem US).
  • Com um SCPH-1001 US genuíno (crc32 37157331) → compila limpo (1 função ignorada). Banner image=SCPH-1001.
  • Resultado : o BIOS retail não corrige o Reset. Assinatura de congelamento idêntica — epc = 0x8013038C, sr = 0x40000404, iec = 0. Bug do runtime da psxrecomp, não do BIOS.

08

Investigação ao vivo (servidor de debug)

Build build-debugtools (servidor de debug na porta 4370). O usuário leva o jogo até o Reset ; o estado congelado é então consultado.

ComandoO que mostra
freeze_checkcop0_epc=0x8013038C, cop0_sr=0x40000404, iec=0, in_exception=0, tudo no interpretador dirty-RAM
cdrom_stateirq_flag=0x03 (INT3 nunca reconhecido) · pending cmd=0x09 (Pause) travada ativa
dispatch_taillaço 0x445C · 0x5000 · 0x1C5C · 0x2104 — código do BIOS na RAM, nenhum código do jogo
thread_ctx_ring3 threads cooperativas : main 0xA000E29C, CD 0xA000E35C, Reset 0xA000E41C
irqctx_ringcongelado desde o frame 3883 — nenhuma interrupção entregue desde então
read_ram 0xA000E3F0slot de SR do TCB da thread do CD = 0x40000404 confirmado na RAM

A transição defeituosa

No frame 3897 : a thread main é salva com sr=0x40000401 (IEc=1, saudável), depois a thread do CD é restaurada com resume_pc=0x80130508 e sr=0x40000404. A partir daí, todo save/restore da thread do CD carrega 0x40000404. Depois, nenhuma troca de thread nunca mais.

O mecanismo

  • Uma interrupção de VBLANK atinge a thread do CD em 0x8013038C. O hardware empilha o SR : 0x40000401 → 0x40000404 (o IEc antigo vai para IEp, o novo IEc vira 0).
  • O kernel salva a thread do CD no TCB dela com esse SR empilhado.
  • No restore, a "cópia bruta" (correção do bug #1) faz cop0_sr = 0x40000404 → IEc fica em 0 para sempre. Nenhum rfe jamais desempilha.
  • IEc=0 → o ACK do CD-ROM (INT3) nunca é atendido → process_pending() bloqueia o comando Pause → falso "CD timeout" → tela preta, round-robin de threads congelado.

09 · CORREÇÃO

O pop condicional

A contradição

A correção do boot precisa de cópia bruta : o slot de SR de uma thread recém-aberta contém 0x40000401, nunca empilhado — um pop perderia o IEc.

A correção do Reset precisa do pop : o slot contém 0x40000404, empilhado pelo hardware — sem o pop, o IEc fica em 0.

As duas passam pelo mesmo psx_restore_context_from_tcb. Discriminante : o bit IEc do SR salvo.

uint32_t saved_sr = cpu->read_word(save + 140u);
if (saved_sr & 0x01u) {
    // IEc setado: thread estacionada com limpeza (yield cooperativo / thread nova)
    cpu->cop0[12] = saved_sr;                                // cópia bruta
} else {
    // IEc zerado: suspensa NO MEIO DE UMA EXCEÇÃO. O restore do scheduler HLE
    // substitui o ReturnFromException do kernel, cujo rfe final desempilha.
    cpu->cop0[12] = (saved_sr & 0xFFFFFFC0u) | ((saved_sr >> 2) & 0x0Fu);
}

pop(0x40000404) = 0x40000401. A mesma regra vale para o fallback de ReturnFromException do syscall(3).

Verificado — ao vivo no servidor de debug e pelo usuário : o menu volta após o Reset, o contador de frames passa de 26.000, wedge: None, zero freeze_dump. Commit no submódulo 36e124d3.

RESUMO DOS COMMITS

Commits

SHARepoO quê
67ba7e8SFEX2PScaffold New Project Layout
8630f88SFEX2PRemoção de BOM · vsync=off (correção 120 Hz)
09ff2311psxrecompfix cópia bruta do SR (reaplicação da bancada de 24 ago)
7b2f0acSFEX2PBump do submódulo — correção de boot
412ec99SFEX2PPad digital · multitap off · overlay_cache=false
433743dSFEX2PBIOS retail SCPH-1001 US
36e124d3psxrecompfix pop rfe do SR no restore quando IEc=0
928b287SFEX2PBump do submódulo — correção do Mode Select

O QUE FICA

Dois bugs de framework para enviar ao upstream

As duas correções de SR (09ff2311 e 36e124d3) ficam no carve-out do scheduler cooperativo de TCB em traps.c — código que todo projeto de recomp compartilha. Nenhuma está no upstream do mstan/psxrecomp.

Nota permanente

A cada bump da psxrecomp contra o master do upstream, reaplicar as duas correções. Elas merecem um PR no upstream : o pop condicional é fiel ao hardware (o rfe desempilha a pilha IEc/KUc) e satisfaz os dois casos com evidência ao vivo.

O BIOS retail SCPH-1001 não é exigido por esta correção — mantido por ser mais fiel que o OpenBIOS.