gpt4 book ai didi

c++ - 如何在Windows异常处理程序中设置MMX寄存器以模拟不受支持的3DNow!指示

转载 作者:可可西里 更新时间:2023-11-01 12:50:35 29 4
gpt4 key购买 nike

我正在尝试复兴使用3DNow的旧Win32游戏!指令集以进行3D渲染。

在Win7-Win10等现代OS上,不允许FPADD或FPMUL之类的Win10指令,并且该程序将引发异常。

自3DNow数量!游戏使用的指令非常有限,在我的VS2008 MFC程序中,我尝试使用矢量化异常处理来获取MMX寄存器的值,模拟3DNow! C代码的指令,然后将值推回处理器3DNow!寄存器。

到目前为止,我已经成功完成了前两个步骤(我从偏移量32处的ExceptionInfo->ExtendedRegisters字节数组中获取mmx寄存器值,并使用浮点类型C指令进行计算),但是我的问题是,无论我如何尝试更新MMX寄存器值,寄存器值似乎保持不变。

假设我的_asm语句可能是错误的,我还使用以下简单语句进行了一些最小的测试:

_asm movq mm0 mm7

该语句的执行没有其他异常(exception),但是在检索MMX寄存器值时,我仍然发现原始值未更改。

如何使作业有效?

最佳答案

On modern OSs like Win7 - Win10 instructions like FPADD or FPMUL are not allowed



您的CPU很可能不支持3DNow! AMD dropped it for Bulldozer-family,英特尔从未支持过。因此,除非您在Athlon64/Phenom(或Via C3)上运行现代Windows,否则您的CPU不支持它。

(有趣的是: PREFETCHW 最初是3DNow!指令,并且仍受支持(具有其自己的CPUID功能位)。很长时间以来,英特尔CPU一直将其作为NOP运行,但Broadwell和更高版本(IIRC)确实预取了缓存行进入拥有所有权读取状态的排他状态。)

除非该游戏只能在AMD硬件上运行,否则它必须具有避免3DNow的代码路径。修复其CPU检测以停止检测到您的CPU具有3DNow。 (也许您拥有最近的AMD,并且假定任何AMD都具有3DNow?)

(对此进行更新: OP's comments say that the other code paths don't work for some reason。这是一个问题。)

从异常处理程序返回的数据可能会从保存的状态中恢复寄存器,因此更改异常处理程序中的寄存器值对主程序没有影响也就不足为奇了。

显然 updating ExtendedRegisters in memory doesn't do the trick,所以那只是保存状态的一个拷贝。

从异常处理程序修改MMX寄存器的答案可能与整数或XMM寄存器的答案相同,因此请查阅MS的文档。

替代建议:

重写3DNow代码以使用SSE2。 (您说的只是其中的一小部分?)。 SSE2是x86-64的基线,通常可以安全地假定为32位x86。

没有源代码,您仍然可以为使用3DNow的一些功能修改asm。您实际上可以更改指令以使用64位加载/存储到XMM寄存器中,而不是3DNow! 64位加载/存储,并将PFMUL替换为 mulps等。(如果寄存器用完并且3DNow代码使用了内存源操作数,这可能会变得有些冗长。 addps xmm0, [mem]需要16B对齐的内存,并进行16字节加载因此,您可能必须添加溢出/重载以借用另一个寄存器作为临时对象)。

如果您没有空间就地重写函数,请将jmp放在您有空间添加新代码的地方。

大多数 the 3DNow instructions在SSE中具有等效功能,但是您可能需要一些额外的 movaps指令来复制寄存器以实现 PFCMPGE。如果您可以忽略NaN的可能性,则可以将 cmpps 与不少于谓词一起使用。 (在没有AVX的情况下,SSE仅具有基于小于或不小于的比较谓词)。
PFSUBR易于使用备用寄存器进行仿真,只需复制和 subps即可反转。 (或SUBPS,然后用XORPS反转符号)。 PFRCPIT1(优化的倒数第一个迭代)等等没有单指令实现,但是如果您不想使用 implement Newton-Raphson iterations with mulps and addps(或使用AVX sqrtps),则可以只使用 divpsvfmadd。现代CPU比该游戏的设计速度要快得多。

您可以使用 movsd(SSE2 double 加载/存储指令)将一对单精度浮点数从存储器/存储到XMM寄存器的低64位/存储到XMM寄存器的低64位。您还可以使用 movlps存储一对,但是仍然使用 movsd进行加载,因为它会将上半部分置零而不是合并,因此它不依赖于寄存器的旧值。

使用 movdq2q mm0, xmm0 movq2dq xmm0, mm0在XMM和MMX之间移动数据。

使用 movaps xmm1, xmm0复制寄存器,即使您的数据仅处于低位。 ( movsd xmm1, xmm0将低半部分合并为原始的高半部分。 movq xmm1, xmm0将高半部分归零。)
addpsmulps在上半部分使用零可以正常工作。 (如果有任何垃圾(上半部分)产生异常结果,它们可能会减慢速度,因此最好将上半部分保持为零)。请参阅 http://felixcloutier.com/x86/以获取指令集引用(以及 标签Wiki中的其他链接)。

FP数据的任何改组都可以使用 shufpspshufd在XMM寄存器中完成,而无需复制回MMX寄存器以使用任何MMX改组。

关于c++ - 如何在Windows异常处理程序中设置MMX寄存器以模拟不受支持的3DNow!指示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46969423/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com