Street Fighter EX2 Plus remis à plat sur la dernière psxrecomp — un scaffold propre, trois bugs runtime, trois correctifs.
Jeu SLUS-01105 · entry 0x801CA7D8Framework psxrecomp v0.3.2-alphaBIOS SCPH-1001 US (LLE)
cop0_sr · thread CD au retour Mode Select
Avant
0x40000404
→
Après
0x40000401
Tout tenait au bit 0 (IEc). Restauré à 0, les interruptions restaient coupées à jamais : écran noir. Le correctif : dépiler le SR (rfe) quand le thread a été suspendu en pleine exception.
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.
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.
Étape
Résultat
build_emitters.sh
émetteurs prêts sous build-recompiler/
generate
51 shards · 1 912 806 lignes de C · table de dispatch 2079 entrées
cmake + ninja
compile 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é
Valeur
Raison
[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_cache
false
Aligné sur le projet sœur Plus Alpha.
[controller] multitap_analog
false
Multitap activé par erreur au scaffold (voir bug #2).
bios_hle / openbios
false / false
Bascule sur BIOS retail SCPH-1001 (voir bug #3).
05 · BUGCORRIGÉ
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 :
Après : tourne au-delà de la frame 9400, iec = 1, sr = 0x40000401, zéro freeze_dump. Commit sous-module 09ff2311.
06 · BUGCORRIGÉ
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 · BUGCORRIGÉ
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é.
Commande
Ce qu'elle montre
freeze_check
cop0_epc=0x8013038C, cop0_sr=0x40000404, iec=0, in_exception=0, tout en interpréteur dirty-RAM
cdrom_state
irq_flag=0x03 (INT3 jamais acquitté) · pending cmd=0x09 (Pause) bloquée active
dispatch_tail
boucle 0x445C · 0x5000 · 0x1C5C · 0x2104 — code BIOS en RAM, aucun code jeu
thread_ctx_ring
3 threads coopératifs : main 0xA000E29C, CD 0xA000E35C, Reset 0xA000E41C
irqctx_ring
figé depuis la frame 3883 — plus aucune interruption livrée
read_ram 0xA000E3F0
case SR du TCB du thread CD = 0x40000404confirmé 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
SHA
Dépôt
Contenu
67ba7e8
SFEX2P
Scaffold New Project Layout
8630f88
SFEX2P
Strip BOM · vsync=off (fix 120 Hz)
09ff2311
psxrecomp
fix SR copie brute (ré-application atelier 24 août)
7b2f0ac
SFEX2P
Bump sous-module — fix boot
412ec99
SFEX2P
Pad digital · multitap off · overlay_cache=false
433743d
SFEX2P
BIOS retail SCPH-1001 US
36e124d3
psxrecomp
fix pop rfe du SR au restore si IEc=0
928b287
SFEX2P
Bump 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.
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 0x801CA7D8Framework psxrecomp v0.3.2-alphaBIOS SCPH-1001 US (LLE)
cop0_sr · CD thread on return to Mode Select
Before
0x40000404
→
After
0x40000401
It all hinged on bit 0 (IEc). Restored as 0, interrupts stayed disabled forever : black screen. The fix : pop the SR (rfe) when the thread was suspended mid-exception.
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.
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.
51 shards · 1,912,806 lines of C · dispatch table 2079 entries
cmake + ninja
compiles 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
Key
Value
Reason
[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_cache
false
Aligned with the sibling Plus Alpha project.
[controller] multitap_analog
false
Multitap enabled by mistake at scaffold (see bug #2).
bios_hle / openbios
false / false
Switch to the retail SCPH-1001 BIOS (see bug #3).
05 · BUGFIXED
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 · BUGFIXED
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 · BUGFIXED
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.
Command
What it shows
freeze_check
cop0_epc=0x8013038C, cop0_sr=0x40000404, iec=0, in_exception=0, all in the dirty-RAM interpreter
cdrom_state
irq_flag=0x03 (INT3 never acknowledged) · pending cmd=0x09 (Pause) stuck active
dispatch_tail
loop 0x445C · 0x5000 · 0x1C5C · 0x2104 — BIOS code in RAM, no game code
thread_ctx_ring
3 cooperative threads : main 0xA000E29C, CD 0xA000E35C, Reset 0xA000E41C
irqctx_ring
frozen since frame 3883 — no interrupt delivered since
read_ram 0xA000E3F0
SR slot of the CD thread's TCB = 0x40000404confirmed 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
SHA
Repo
What
67ba7e8
SFEX2P
New Project Layout scaffold
8630f88
SFEX2P
Strip BOM · vsync=off (120 Hz fix)
09ff2311
psxrecomp
fix raw SR copy (re-apply 24 Aug workshop)
7b2f0ac
SFEX2P
Submodule bump — boot fix
412ec99
SFEX2P
Digital pad · multitap off · overlay_cache=false
433743d
SFEX2P
Retail SCPH-1001 US BIOS
36e124d3
psxrecomp
fixrfe pop of SR on restore when IEc=0
928b287
SFEX2P
Submodule 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.
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 0x801CA7D8Framework psxrecomp v0.3.2-alphaBIOS SCPH-1001 US (LLE)
cop0_sr · thread do CD ao voltar ao Mode Select
Antes
0x40000404
→
Depois
0x40000401
Tudo dependia do bit 0 (IEc). Restaurado como 0, as interrupções ficavam desligadas para sempre : tela preta. A correção : desempilhar o SR (rfe) quando a thread foi suspensa no meio de uma exceção.
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.
Etapa
Resultado
build_emitters.sh
emitters prontos em build-recompiler/
generate
51 shards · 1.912.806 linhas de C · tabela de dispatch com 2079 entradas
cmake + ninja
compila 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
Chave
Valor
Motivo
[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_cache
false
Alinhado ao projeto irmão Plus Alpha.
[controller] multitap_analog
false
Multitap ativado por engano no scaffold (ver bug #2).
bios_hle / openbios
false / false
Troca para o BIOS retail SCPH-1001 (ver bug #3).
05 · BUGCORRIGIDO
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 :
Depois : roda além do frame 9400, iec = 1, sr = 0x40000401, zero freeze_dump. Commit no submódulo 09ff2311.
06 · BUGCORRIGIDO
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 · BUGCORRIGIDO
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.
Comando
O que mostra
freeze_check
cop0_epc=0x8013038C, cop0_sr=0x40000404, iec=0, in_exception=0, tudo no interpretador dirty-RAM
cdrom_state
irq_flag=0x03 (INT3 nunca reconhecido) · pending cmd=0x09 (Pause) travada ativa
dispatch_tail
laço 0x445C · 0x5000 · 0x1C5C · 0x2104 — código do BIOS na RAM, nenhum código do jogo
thread_ctx_ring
3 threads cooperativas : main 0xA000E29C, CD 0xA000E35C, Reset 0xA000E41C
irqctx_ring
congelado desde o frame 3883 — nenhuma interrupção entregue desde então
read_ram 0xA000E3F0
slot de SR do TCB da thread do CD = 0x40000404confirmado 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
SHA
Repo
O quê
67ba7e8
SFEX2P
Scaffold New Project Layout
8630f88
SFEX2P
Remoção de BOM · vsync=off (correção 120 Hz)
09ff2311
psxrecomp
fix cópia bruta do SR (reaplicação da bancada de 24 ago)
7b2f0ac
SFEX2P
Bump do submódulo — correção de boot
412ec99
SFEX2P
Pad digital · multitap off · overlay_cache=false
433743d
SFEX2P
BIOS retail SCPH-1001 US
36e124d3
psxrecomp
fix pop rfe do SR no restore quando IEc=0
928b287
SFEX2P
Bump 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.