В современных ОС, таких как Win7 - Win10, такие инструкции, как FPADD или FPMUL, не разрешены.
Скорее всего ваш процессор не поддерживает 3DNow! AMD отказалась от него для семейства Bulldozer, а Intel никогда его не поддерживала. Поэтому, если вы не используете современную Windows на Athlon64/Phenom (или Via C3), ваш процессор не поддерживает ее.
(Забавный факт: PREFETCHW
изначально была инструкцией 3DNow!, а является по-прежнему поддерживается (с собственным битом функции CPUID). Долгое время процессоры Intel запускали его как NOP, но Broadwell и более поздние версии (IIRC) фактически предварительно загружают строку кэша в монопольное состояние с помощью Read-For-Ownership.)
Если эта игра когда-либо работала только на оборудовании AMD, у нее должен быть путь кода, который позволяет избежать 3DNow. Исправьте его обнаружение ЦП, чтобы перестать определять ваш ЦП как имеющий 3DNow. (Может быть, у вас недавний AMD, и предполагается, что у любого AMD есть 3DNow?)
(обновить: Комментарии ОП говорят, что другие пути кода по какой-то причине не работают. Это проблема.)
Возврат из обработчика исключений, вероятно, восстанавливает регистры из сохраненного состояния, поэтому неудивительно, что изменение значений регистров в обработчике исключений не влияет на основную программу.
По-видимому, обновление ExtendedRegisters
в памяти не помогает, так что это всего лишь копия сохраненного состояния.
Ответ на изменение регистров MMX из обработчика исключений, вероятно, такой же, как и для целочисленных регистров или регистров XMM, поэтому поищите для этого документацию MS.
Альтернативное предложение:
Перепишите код 3DNow для использования SSE2. (Вы сказали, что их очень мало?). SSE2 является базовым для x86-64 и, как правило, безопасно для 32-разрядной архитектуры x86.
Без исходного кода вы все равно можете изменить asm для нескольких функций, использующих 3DNow. Вы можете буквально просто изменить инструкции для использования 64-битных загрузок/сохранений в регистры XMM вместо 3DNow! 64-битные загрузки/сохранения и замена PFMUL на mulps
и т. д. (Это может стать немного неудобным, если у вас закончатся регистры, а код 3DNow использует операнд-источник памяти. addps xmm0, [mem]
требует выровненной по 16 байтам памяти и выполняет 16-байтовую загрузку. Так что вам, возможно, придется добавить пролив/перезагрузку, чтобы позаимствовать еще один регистр как временный).
Если у вас нет места для перезаписи функций на месте, поставьте jmp
там, где у вас есть место для добавления нового кода.
Большинство инструкций 3DNow имеют эквиваленты в SSE, но вам могут понадобиться дополнительные movaps
инструкции по копированию регистров для реализации PFCMPGE
. Если вы можете игнорировать возможность NaN, вы можете использовать cmpps
с не менее чем предикат. (Без AVX в SSE есть только предикаты сравнения, основанные на меньшем или не меньшем).
PFSUBR
легко эмулировать с помощью запасного регистра, просто скопируйте и subps
реверсируйте. (Или SUBPS и инвертировать знак с помощью XORPS). PFRCPIT1
(первая итерация уточнения reciprocal-sqrt) и т. д. не имеют реализации с одной инструкцией, но вы, вероятно, можете просто использовать sqrtps
и divps
, если вы не хотите реализовать итерации Ньютона-Рафсона с помощью mulps и addps (или с помощью AVX vfmadd
). Современные процессоры намного быстрее, чем то, для чего была разработана эта игра.
Вы можете загрузить/сохранить пару чисел с плавающей запятой одинарной точности из/в память в нижние 64 бита регистра XMM, используя movsd
(инструкция загрузки/сохранения двойной точности SSE2). Вы также можете сохранить пару с movlps
, но по-прежнему использовать movsd
для загрузки, потому что он обнуляет старшую половину вместо слияния, поэтому он не зависит от старого значения регистра.
Используйте movdq2q mm0, xmm0
и movq2dq xmm0, mm0
для перемещения данных между XMM и MMX.
Используйте movaps xmm1, xmm0
для копирования регистров, даже если ваши данные находятся только в младшей половине. (movsd xmm1, xmm0
объединяет младшую половину с исходной старшей половиной. movq xmm1, xmm0
обнуляет старшую половину.)
addps
и mulps
прекрасно работают с нулями в верхней половине. (Они могут замедлиться, если какой-либо мусор (в верхней половине) приводит к денормальному результату, поэтому лучше оставить верхнюю половину обнуленной). Справочник по набору инструкций см. на http://felixcloutier.com/x86/ (и другие ссылки в x86 пометить вики.
Любое перетасовка данных FP может выполняться в регистрах XMM с shufps
или pshufd
вместо копирования обратно в регистры MMX для использования любых перетасовок MMX.
person
Peter Cordes
schedule
27.10.2017
CPUID
). - person Peter Cordes   schedule 27.10.2017_asm movq mm0 mm7
внутри своего обработчика исключений? Разве вы не должны обновлятьExtendedRegisters
в памяти перед возвратом из исключения? Я предполагаю, что возврат из обработчика исключений заменяет текущие регистры сохраненными регистрами, поэтому все, что вы оставляете в регистрах перед возвратом, сдувается. (Такой дизайн ОС позволяет обработчикам исключений использовать обычное соглашение о вызовах вместо сохранения/восстановления всех регистров.) - person Peter Cordes   schedule 27.10.2017AuthenticAMD
в строке поставщика? Но в любом случае, нельзя ли просто исправить его, чтобы он не обнаруживал MMX, чтобы он использовал резервный x87? Это будет быстрее, чем делать исключения для каждой математической инструкции в программном рендерере! Если вы хотите, чтобы это было быстрее, подумайте о том, чтобы переписать некоторые из горячих функций на C, чтобы современный компилятор мог использовать SSE2 (и, возможно, авто-векторизацию). - person Peter Cordes   schedule 30.10.2017PFMUL
. (Это PFMUL, а не FPMUL) - person Peter Cordes   schedule 30.10.2017