Festlegen von MMX-Registern in einem Windows-Ausnahmehandler zum Emulieren nicht unterstützter 3DNow! Anleitung

9

Ich versuche ein altes Win32-Spiel wiederzubeleben, das 3DNow! Befehlssatz, um 3D-Rendering zu machen.

Auf modernen Betriebssystemen wie Win7 - Win10 Anweisungen wie FPADD oder FPMUL sind nicht erlaubt und das Programm löst eine Ausnahme aus.

Da die Anzahl der 3DNow! Anweisungen, die vom Spiel verwendet werden, sind sehr begrenzt, in meinem VS2008 MFC-Programm habe ich versucht, vektorielle Ausnahmebehandlung zu verwenden, um den Wert von MMX-Registern zu erhalten, emulieren Sie das 3DNow! Anweisungen von C-Code und drücken Sie die Werte zurück zum Prozessor 3DNow! registriert.

Bisher gelang es mir in den ersten zwei Schritten (ich bekomme mmx Registerwerte von ExceptionInfo->ExtendedRegisters byte array bei Offset 32 ​​und verwende float Typ C Anweisungen um Berechnungen durchzuführen), aber mein Problem ist das, egal wie ich versuche zu aktualisieren Bei den MMX-Registerwerten scheinen die Registerwerte unverändert zu bleiben.

Angenommen, meine _asm -Anweisungen könnten falsch sein, habe ich auch einen minimalen Test mit einfachen Anweisungen wie folgt gemacht:

%Vor%

Diese Anweisung wird ohne weitere Ausnahmen ausgeführt, aber beim Abrufen der MMX-Registerwerte finde ich immer noch, dass die ursprünglichen Werte unverändert waren.

Wie kann ich die Aufgabe effektiv machen?

    
gho 27.10.2017, 07:10
quelle

1 Antwort

4
  

Auf modernen Betriebssystemen wie Win7 - Win10 Anweisungen wie FPADD oder FPMUL sind nicht erlaubt

Wahrscheinlich unterstützt Ihre CPU 3DNow nicht! AMD hat es für die Bulldozer-Familie fallen lassen und Intel hat es nie unterstützt. Wenn Sie also kein modernes Windows auf einem Athlon 64 / Phenom (oder einem Via C3) betreiben, wird dies von Ihrer CPU nicht unterstützt.

(Wissenswertes: PREFETCHW war ursprünglich eine 3DNow! -Anweisung und ist wird noch unterstützt (mit seinem eigenen CPUID-Feature-Bit). Lange Zeit haben Intel-CPUs es als NOP ausgeführt, aber Broadwell und später (IIRC) holen eine Cache-Zeile tatsächlich mit einem Read-For-Ownership in den Exklusiv-Zustand. p>

Wenn dieses Spiel niemals auf AMD-Hardware läuft, muss es einen Code-Pfad haben, der 3DNow vermeidet. Fixiere die CPU-Erkennung, um zu verhindern, dass deine CPU 3DNow erkennt. (Vielleicht haben Sie eine aktuelle AMD, und es wird davon ausgegangen, jede AMD hat 3DNow?)

(Update dazu: Kommentare von OP sagen, dass die anderen Codepfade aus irgendeinem Grund nicht funktionieren . Das ist ein Problem.

Bei der Rückkehr von einem Exception-Handler werden wahrscheinlich Register aus dem gespeicherten Zustand wiederhergestellt. Es ist daher nicht verwunderlich, dass das Ändern von Registerwerten im Exception-Handler keine Auswirkungen auf das Hauptprogramm hat.

Offenbar update ExtendedRegisters im Speicher tut das nicht , also ist das nur eine Kopie des gespeicherten Zustands.

Die Antwort zum Ändern von MMX-Registern von einem Ausnahmebehandler ist wahrscheinlich die gleiche wie für Integer- oder XMM-Register. Suchen Sie dazu in der Dokumentation von MS nach.

Alternativvorschlag:

Schreiben Sie den 3DNow-Code erneut, um SSE2 zu verwenden. (Sie sagten, es gibt nur eine kleine Menge davon?) . SSE2 ist Basis für x86-64 und im Allgemeinen sicher für 32-Bit x86 anzunehmen.

Ohne Quelle können Sie die ASM für die wenigen Funktionen, die 3DNow verwenden, ändern. Sie können buchstäblich nur die Anweisungen ändern, um 64-Bit-Ladungen / Speicher in XMM-Registern anstelle von 3DNow zu verwenden! 64-bit lädt / speichert und ersetzt PFMUL durch mulps usw. (Dies könnte leicht behaart werden, wenn Sie keine Register mehr haben und der 3DNow-Code einen Speicherquellenoperanden verwendet.% Co_de% benötigt 16B-ausgerichteten Speicher und tut dies auch eine 16-Byte-Last. Sie müssen also möglicherweise ein Überlauf / Neuladen hinzufügen, um ein anderes Register als temporäres auszuleihen.)

Wenn Sie keinen Platz haben, um die Funktionen vor Ort zu überschreiben, fügen Sie addps xmm0, [mem] ein, um Platz für neuen Code zu schaffen.

Die meisten 3DNow-Anweisungen haben Entsprechungen in SSE, aber Sie benötigen möglicherweise zusätzliche jmp -Anweisungen um Register zu kopieren, um movaps zu implementieren. Wenn Sie die Möglichkeit von NaN ignorieren können, können Sie PFCMPGE mit einem Nicht-weniger-als-Prädikat verwenden. (Ohne AVX hat SSE nur Vergleichsprädikate, die auf "weniger als" oder "nicht weniger" basieren.)

cmpps ist einfach mit einem Ersatzregister zu emulieren, kopieren Sie einfach und PFSUBR um umzukehren. (Oder SUBPS und invertiere das Zeichen mit XORPS). subps (reziprok-sqrt erste Iteration der Verfeinerung) und so weiter haben keine Einzelinstruktions-Implementierung, aber Sie können wahrscheinlich einfach PFRCPIT1 und sqrtps verwenden, wenn Sie nicht Implementieren von Newton-Raphson-Iterationen mit mulps und addps (oder mit AVX divps ). Moderne CPUs sind viel schneller als das, wofür dieses Spiel entwickelt wurde.

Sie können ein Paar Gleitkommazahlen einfacher Genauigkeit von / in den Speicher in die unteren 64 Bits eines XMM-Registers laden / speichern, indem Sie vfmadd verwenden (die SSO2-Lade- / Speicheranweisung mit doppelter Genauigkeit). Sie können auch ein Paar mit movsd speichern, aber immer movlps zum Laden verwenden, da es die obere Hälfte zerlegt, anstatt zu verschmelzen, so dass es keine Abhängigkeit vom alten Wert des Registers hat.

Verwenden Sie movsd und movdq2q mm0, xmm0 , um Daten zwischen XMM und MMX zu verschieben.

Verwenden Sie movq2dq xmm0, mm0 , um Register zu kopieren, auch wenn Ihre Daten nur in der unteren Hälfte liegen. ( movaps xmm1, xmm0 führt die untere Hälfte in die ursprüngliche obere Hälfte zusammen. movsd xmm1, xmm0 setzt die obere Hälfte auf Null.)

movq xmm1, xmm0 und addps funktionieren gut mit Nullen in der oberen Hälfte. (Sie können langsamer werden, wenn irgendein Müll (in der oberen Hälfte) ein denormales Ergebnis erzeugt, also bevorzugen Sie, die obere Hälfte auf Null zu setzen). Siehe Ссылка für eine Befehlssatzreferenz (und andere Links im Tag-Wiki.

Jedes Shuffling von FP-Daten kann in XMM-Registern mit mulps oder shufps erfolgen, anstatt in MMX-Register zurück zu kopieren, um die MMX-Shuffle zu verwenden.

    
Peter Cordes 27.10.2017 07:43
quelle

Tags und Links