目录
6 加载和存储单元
6.1 概述
6.2 加载和存储单元
6.3 寻址模式
6.3.1 间接寻址模式
6.3.2 索引寻址模式
6.3.3 直接寻址模式
6.3.4 堆栈寻址模式
6.3.4 IBA相对寻址
6 加载和存储单元
6.1 概述
加载和存储单元(LSU)执行以下操作:
- 生成数据的地址
- 执行数据内存加载和存储操作
- 打开并打包加载和存储的数据
- 将其写入/读取处理器的内部寄存器
LSU包括两个名为LS0和LS1的加载和存储单元。LS0用于从存储器加载数据,LS1用于将数据存储到存储器中。
LS0和LS1单元支持以下主要机制:
- 根据一种寻址模式生成32位地址的线性地址。该地址指向数据存储器空间中的字节位置。
- SPU、LSU和PCU单元的读取带宽为128位,写入带宽为128比特。这使得LS0和LS1都可以通过字节对齐来读取和写入其最大带宽。
- 有两种类型的地址寄存器编辑:线性编辑和模数编辑。每个LSU都可以编辑通用寄存器或堆栈指针。
- 多循环操作。某些操作可以加载或存储超过128位。在这种情况下,单个指令在多个周期内执行。
LS0和LS1单元连接到通用通用寄存器文件(GRF)。GRF包含32位寄存器、通用寄存器、步进寄存器和堆栈指针寄存器。
所有LSU指令都可以使用其中一个断言(predicate)寄存器进行条件运算。SPU包含可以影响断言(predicate)寄存器的专用指令。LSU指令只支持标量预测,这意味着整个指令要么被执行,要么不被执行。
图6-1.LSU框图
以下部分描述LSU及其支持的寻址机制。
6.2 加载和存储单元
LSU包含两个独立的加载和存储单元:LS0从存储器加载数据,LS1将数据存储到存储器。每个单元支持两个主要机制:
- 地址生成
- 指针编辑
地址生成机制根据指令中指定的寻址模式计算单个32位地址。然后,将地址连同读/写选通和访问宽度一起提供给数据存储器。地址指向字节位置。
由于每个单元可以生成单个地址,因此可以同时生成总共两个地址:一个用于从存储器加载数据,另一个用于将数据存储到存储器。
LS0和LS1单元支持一组用于访问数据存储器的指令,如中所述。表6-1
表6-1. 内存访问指令
说明书 | LS0/LS1 | 描述 |
ld | LS0 | 将内存操作数从数据内存加载到SPU、LSU或PCU寄存器中 |
st | LS1 | 将SPU、LSU或PCU寄存器或其部分存储到数据存储器中 |
pop | LS0 | 将操作数从软件堆栈弹出到SPU、LSU或PCU寄存器 |
push | LS1 | 将SPU、LSU或PCU寄存器推入软件堆栈 |
LS0和LS1单元通过Little Endian方法访问内存,这意味着LSB存储在最低地址中。
以下部分描述了LS0和LS1单元支持的不同寻址模式,以及有关支持的访问类型和指针修改机制的详细信息。
注:规格适用于LS0和LS1单元。
6.3 寻址模式
每个LSU支持以下寻址模式:
- 间接,6.3.1, 间接 寻址 模式
- 索引,6.3.2, 索引 寻址 模式
- 直接,6.3.3, 直接 寻址 模式
- 堆栈,6.3.4, 堆栈 寻址 模式
由于LS0和LS1是独立的单元,因此它们中使用的寻址模式可以不同。寻址模式在指令中使用专用语法指定。该语法在每个寻址模式的相关部分中进行了描述。
6.3.1 间接寻址模式
在间接寻址模式下,GRF寄存器包含32位地址。间接寻址模式使用线性模式方法,这意味着地址是指针的内容。指针寄存器可以事后修改。
示例 6-1 演示了间接寻址模式。
例6-1.线性模式下的间接寻址
mov #0x1004,r4.ui; r4 contains the address 0x1004. nop nop ld (r4.ui).s+, r0.i ; Loads short from address 0x1004 into r0. |
6.3.2 索引寻址模式
在索引寻址模式中,地址是基址寄存器和偏移量的总和。基址寄存器可以是32个GRF寄存器和堆栈指针中的任何一个。偏移可以是以下之一:
- GRF寄存器
- 高达16位的有符号立即数
尽管偏移量被添加到基址寄存器,但基址寄存器保持不变。
偏移量包含许多字节,并且不会根据访问类型自动缩放。
当寄存器指定偏移量时,可以对其进行后期修改。有关修改后选项的更多详细信息,请参阅第6.4节,指针修改机制。
索引寻址模式的语法在表 6-2列出。
表6-2.索引寻址模式语法
寻址模式 | 语法 | |
Indexed | Offset is a register | (rM.ui + rN.[u]i) |
Offset is a signed 16-bit immediate value | (rM + #immN16) |
下面的示例演示索引寻址模式的使用。
例6-2.以指针作为偏移量索引
mov #0x004,r0.ui; Initializes the base register r0. mov #0x100,r3.i; Initializes the offset pointer r3. nop nop st r7.i,(r0.ui+r3.i).i; An integer is stored at address 0x104. ; r0 is kept unchanged. ; r3 is post-modified and its value after ; the store instruction execution is 0x104. |
例6-3.以立即数作为偏移量索引
mov #0x010,r1.ui; Initializes the base register r1. nop nop ld (#300+r1.ui).s, r7.i ; Loads a short integer from address 0x310. ; r1 is kept unchanged. |
6.3.3 直接寻址模式
在直接寻址模式下,整个32位地址在指令中显式指定。当地址是32位无符号立即数时,直接寻址模式在指令中由语法[#address]指定。示例 6-4 演示此寻址模式的用法。
实施例6-4.直接寻址
st r0.i,r4.i,(#0x1000A234).s2; Two words are stored at address ; 0x1000_A234. |
6.3.4 堆栈寻址模式
GRF包含一个32位堆栈指针寄存器,称为sp,它指向压入软件堆栈的最后一个值。该软件堆栈可以驻留在数据空间中的任何位置。
由于堆栈是从高内存地址填充到低内存地址的,因此当新操作数被推送到堆栈上时,堆栈指针在生成内存写入地址之前递减。以相同的方式,当操作数从堆栈中弹出时,堆栈指针在生成内存读取地址后递增。堆栈指针用于pop、push、ld和st指令。每个指令都对软件堆栈和堆栈指针执行专用操作。通常,堆栈指针会根据指令中定义的访问宽度自动修改。下表列出了根据各种指令进行的堆栈指针修改。
表6-3. 堆栈指针修改
说明书 | 堆栈指针修改 |
pop{ch1} | sp+1 |
pop{sh1} | sp+2 |
pop{1} | sp+4 |
pop{ch2} | sp+2 |
pop{sh2} | sp+4 |
pop{in2} | sp+8 |
pop{ch4} | sp+4 |
pop{sh4} | sp+8 |
pop{in4} | sp+16 |
push{ch1} | sp-1 |
push{sh1} | sp-2 |
push{1} | sp-4 |
push{ch2} | sp-2 |
push{sh2} | sp-4 |
push{in2} | sp-8 |
push{ch4} | sp-4 |
push{sh4} | sp-8 |
push{in4} | sp-16 |
push指令可以在堆栈中存储多个操作数。指令中的第一个(最左侧)操作数是堆栈中要推入的第一个操作数,如例6-5中所示。
实施例6-5. push指令
Assuming that the following instruction is executed:
push{sh4} r7.i, r13.i, r4.i, r10.i
And assuming:
r7=0x0000ABCD, r13= 0x00005678
r4= 0x00001234, r10 = 0x0000DCBA
The following figure shows the stack before and after the push instructions:
操作数按它们在推送指令中出现的顺序(即从左到右)存储在堆栈中,这意味着r10在堆栈中被推到最后。堆栈指针递减八个字节。数据存储为Little Endian,这意味着LSB存储在最低地址。
pop指令还可以加载多个操作数。指令中的第一个(最左侧)操作数是第一个要加载的操作数。此规则也适用于并行弹出指令,如例6-6中所示。
实施例6-6. pop指令
Assuming that the following instruction is executed:
pop{in1} r17.i
The following figure shows the stack before and after the pop{i1} instruction:
内存操作数加载到r17寄存器中,堆栈指针递增四个字节。数据从内存中弹出为Little Endian,这意味着LSB被弹出到r17的最低字节。
在pop{i1}指令之后,r17的内容是0xABCD1234。
6.3.4 IBA相对寻址
特殊LD指令基于与IBA寄存器的偏移量从存储器加载32位(如第3.4.3节,即时基址寄存器中所述)。IBA寄存器指向数据存储器中的一个部分,该部分保存应用程序使用的32位立即数表。通过内存访问这些值比将它们直接编码为具有32位立即数操作数的mov指令更具代码效率。
有效使用此指令的能力基于软件工具支持的编译后流,其中收集整个应用程序中使用的32位立即数符号,并根据其使用频率进行排序。结果列表被加载到数据存储器中的一个部分,其中最频繁的值首先列出。这使得可以使用更短的ld变量来访问它们(最短的变量是16位长)。
6.3.5 mpush/mpop指令
以下多周期指令用于在跳转到函数后从函数返回之前最小化存储和恢复寄存器所需的代码占用:
- mpush:执行一系列推送事务的单个指令。它实现编译器通常在函数序言中使用的操作,并将被调用方保存的寄存器保存在堆栈中。
mpush指令还可以选择执行frmalloc操作并存储PRDR寄存器。
- mpop:执行一系列弹出事务的单个指令。它实现编译器通常在函数的尾声中使用的操作,并在从函数返回之前从堆栈中还原被调用方保存的寄存器。
mpop指令还可以选择性地执行与mpop的一系列pop操作并行执行的ret。
mpop指令还可以选择执行frmrestore操作并还原PRDR寄存器。
因为编译器约定被调用方保存的寄存器是r9-r23,所以mpush指令开始从r9向前推。帧寄存器(r8)通过隐含的frmalloc和frmrestore指令存储和恢复。