我曾经玩过诸如Nasm,Tasm或Masm之类的CPU组装编程,但是我真的很想知道GPU现在是如何工作的。我听说过Cuda和OpenCL,但这不是我想要的。
我想知道GPU指令在RAM中的状态如何...大多数GPU的Nasm和Masm是什么?什么是x86或Z80 GPU(不同的GPU系列)?您知道构造函数操作码参考手册吗?
我认为我确实需要在两个处理单元之间进行比较以明确说明,因为在Internet上学习GPU汇编编程似乎是一个更加困难的课题,那就是CPU组件编程。我还读过“ NVIDIA从未发布过有关其硬件实际理解的指令的详细信息”,但对我来说似乎很令人惊讶。完整文章在这里:https://stackoverflow.com/questions/4660974/how-to-create-or-manipulate-gpu-assembler?newreg=e31519279ce949f087df6322dbf2bf4d
感谢您的帮助!

评论

这篇博客文章介绍了AMD GCN组件的外观(与其他GPU供应商不同,实际上已公开记录了该组件)。

还有stackoverflow.com/questions/1697842/…和stackoverflow.com/questions/7353136/…

另请参见gpuopen.com/compute-product / ...

#1 楼

您倾向于在风车上尝试学习“ GPU组装”,这是由于CPU和GPU的制造和销售方式之间的差异。

每个CPU都有所谓的指令集体系结构x86或ARMv8。指令集是CPU用户(即程序员)和芯片之间的接口。芯片设计人员会发布指令集的详细信息,以便编译器供应商可以编写针对该指令集的编译器。使用该指令集的任何CPU都可以运行相同的二进制文件。 (诸如SSE之类的扩展名使这一点有些虚假,但它们仅添加了新的指令:它们不会更改二进制文件的结构。)当供应商创建新的处理器系列时,其内部可能具有完全不同的微体系结构,但相同指令集。

GPU根本不是这样。为了获得最佳效率,指令集通常与CPU的微体系结构紧密相关。这意味着每个新的GPU系列都有一个新的指令集。 GPU无法运行为不同GPU创建的二进制文件。因此,通常不会发布指令集:相反,您到GPU的接口是供应商为每个图形API(OpenGL,Vulkan,DirectX等)发布的驱动程序。这就是为什么图形API具有获取着色器的源代码并运行它的功能的原因:编译的着色器只能在为其编译的相同模型或GPU系列上运行。

GPU汇编语言是SPIR-V。这是行业标准的中间表示形式,GPU供应商已开始支持该中间表示形式。这就像LLVM的中间表示形式的GPU等效。它允许您预先进行编译的解析和源优化部分,以获得SPIR-V文件,然后GPU驱动程序只需要在加载时将其编译为GPU的指令集即可。

评论


$ \ begingroup $
感谢您的回答!集会对我有帮助:)。关于着色器示例的部分,我不确定我是否理解得很好,但是我认为您的意思是着色器不是编译和组装而是仅编译而不是组装,因为每个GPU的指令集都不相同来自同一个“家庭”。
$ \ endgroup $
–塞巴斯蒂安finor
18年7月16日在21:25



$ \ begingroup $
@sebastienfinor我要说的是,在编译过程中不一定有中间的“汇编语言”表示形式。
$ \ endgroup $
–丹·赫尔姆
18年7月17日在8:17

$ \ begingroup $
首次引入可编程着色器时,它们是使用非常类似于“汇编语言”的语言进行编程的。仍然可以在当时的书籍和论文中找到它。一些游戏编程瑰宝书中的文章都提供了示例。原始的“橙色书”中也有一些。看起来很有趣,因为您会看到fma之类的早期功能。它还可以填补一些“为什么要这样做呢”的问题。并且,您将很快看到不同的供应商具有不同的“语言”。
$ \ endgroup $
–pmw1234
20年7月23日,0:19

$ \ begingroup $
实际上仍然存在多个层,但是程序员实际上并没有访问这些层的权限。例如,GLSL编译为SPIR-V(如前所述),而这些实际上是您作为图形程序员可以访问的唯一语言层。但是在驱动程序代码中,您会发现大量供应商特定的代码...当此代码实际进入gpu时,它会进一步翻译成微代码,微代码才是真正发生的事情,除此之外,这只是数字的海洋。微代码是供应商“修复”硬件错误的方式。通过围绕它们编程。
$ \ endgroup $
–pmw1234
20年7月23日,0:32

#2 楼

您所读的内容是正确的。通常,GPU供应商不会发布其GPU的机器指令列表。

也就是说,您可以使用OpenGL ARB汇编语言在GPU上进行类似于汇编编程的操作。它允许您以汇编样式进行编程,每行编写1个操作码及其操作数。尽管这与为CPU编写汇编语言并不完全相同,但与您可能获得的语言差不多。我相信它在现代OpenGL中已弃用(尽管不是肯定的)。从OpenGL 2.1开始仍然有效。

评论


$ \ begingroup $
我来看一下。感谢您的信息和链接:)。
$ \ endgroup $
–塞巴斯蒂安finor
18年7月16日在21:28

#3 楼

正如其他人所说的那样,GPU公开了一种高级语言,该语言允许多种不同的体系结构(即不同的供应商和不同的GPU代)都支持相同的应用程序。
[更新:链接到较旧ISA的较新ISA代替]
但是,如果您仍然感到好奇,则可以获取有关最新PowerVR指令集的文档-我最喜欢的操作码是“ FRED”和“ FARCTANC” :-)
请注意,指令集可以从一代到一代因此,这主要是出于说明目的。

#4 楼

对于Nvidia GPU,有几种机器语言都可以在这里阅读:
https://docs.nvidia.com/cuda/cuda-binary-utilities/index.html#instruction-set-ref
在“指令集参考”部分上方,还有一些关于SASS代码的SM70变体的示例,这些示例也存储在ELF中并从那里转储,因此它是一种机器代码,因为出于历史原因,ELF始终是不受管代码容器(除了PE可能包含CIL托管代码,但即使在这种情况下,它也必须位于数据部分中,而ELF根本不支持这种令人困惑的功能),它也不是托管/虚拟字节码或某些用户所说的东西,它是真正的本机编译设备代码GPU。正确的指令是用大写字母和十六进制地址写的指令(例如/ * 0000 * / MOV R1,c [0x0] [0x28];),其他指令只是PTX,实际上与题。缺点是,如果分发者选择以预编译形式而不是源代码或至少便携式PTX形式发布GPU程序,则可能需要使用胖子技术。但这是非常罕见的,因为周围没有像CPU二进制文件这样的程序。无论如何,此类代码通常包含在通过调用“ cuModuleLoad”动态加载的立方文件中,然后使用“ cuModuleGetFunction”重写指向设备GPU函数句柄的指针,然后调用“ cuLaunchKernel”,这会强制驱动程序将二进制代码发送到GPU并启动从0地址开始执行,因为所有内核都从0开始(实际上Nvidia使用的ELF变体包含许多部分,但驱动程序仅发送所需的内核代码及其子例程和数据(如交换数据等))。指令本身又如何呢?它们大多是RISC形式的。没有div或mod,而是nvcc编译器必须输出基于加法,减法,乘法,移位,按位逻辑运算(按位以及大部分)的复杂算法。只有寻址模式才能提醒某些CISC的出现,例如“ LD R2,[R2 + 0x1c];”。等

评论


$ \ begingroup $
如果您a)在每个句子中使用更少的连词,并且b)在某些段落中使用,您的答案将更容易理解。
$ \ endgroup $
–西蒙F
20-09-29在8:02