Hexagon DSP的十二种寻址模式

时间:2022-11-28 03:12:08

Hexagon DSP的十二种寻址模式
Hexagon DSP的十二种寻址模式

绝对寻址
绝对寻址模式将32位的值作为有效内存地址。例如:

R2 = memw(##100000) // load R2 with word from addr 100000 memw(##200000) = R4 // store R4 to word at addr 200000

绝对偏移寻址
绝对偏移寻址模式将32位的常数对其至指定的通用寄存器,然后使用该值作为有效的内存地址。例如:

R2 = memw(R1=##400000) // load R2 with word from addr 400000 // and load R1 with value 400000 memw(R3=##600000) = R4 // store R4 to word at addr 600000 // and load R3 with value 600000

寄存器绝对偏移寻址
寄存器绝对偏移寻址模式根据2位寄存器中存储的值对32位通用寄存器的值算术左移,然后将移位后的32位常数相加来获得32位的有效内存地址。例如:

R2 = memh(##100000 + R3 << 3) // load R2 with signed halfword
// from addr [100000 + (R3 << 3)]

在汇编语言的编写中,偏移值通常会通过寄存器来指定字节偏移量。
注:这种地址模式用于从全局表中导入元素,在全局表中可将立即数值作为表格的名称,寄存器保存的是元素的编号。
全局指针相对寻址
全局指针相对寻址模式将一个无符号偏移值加到Hexagon处理器的全局数据指针GP中来创建一个32位的有效内存地址。这种寻址模式用于C语言中访问全局或静态数据。
全局指针相对寻址可以使用两种方式来表达:
 通过清晰将无符号偏移量的值加至寄存器GP
 通过指定寄存器偏移量作为指令操作数
例如:

R2 = memh(GP+#100) // load R2 with signed halfword // from [GP + 100 bytes] R3 = memh(#200) // load R3 with signed halfword // from [GP + 200 bytes]

全局数据指针在GP寄存器中被定义。该区域包含了一个无符号26位的值,用于指定32位指针的位置。
指向全局数据指针的内存也被称作全局数据区域。它可被扩展至512kb长度,此外,由于我们已经定义了全局数据指针的方式,因此该该区域必须对齐64位字节。
若使用汇编编程,全局间接寻址的指针偏移量必须要指针前定义好。而且偏移量必须是指令数据类型的倍数。
Hexagon DSP的十二种寻址模式

间接寻址
间接寻址模式通过存储在通用寄存器中的32位值来指定有效内存空间,例如:

R2 = memub(R1) // load R2 with unsigned byte from addr R1

间接偏移寻址
间接偏移寻址将一个有符号整数加入通用寄存器中使之创建一个有效的32位内存地址。例如:

R2 = memh(R3 + #100) // load R2 with signed halfword
// from [R3 + 100 bytes]

若用汇编语言来表示,偏移量通常定义为寄存器值的偏移。下图列出了偏移量的值
Hexagon DSP的十二种寻址模式

寄存器间接偏移寻址
寄存器间接偏移寻址将32位寄存器的值加至结果从而实现一个双32位通用寄存器值的算术左移,该结果指向一个32位的有效内存空间。例如:

R2 = memh(R3+R4<<#1) // load R2 with signed halfword
// from [R3 + (R4 << 1)]

寄存器的值用于指代字节地址
间接自增立即数寻址
间接自增立即数寻址通过一个存储在32位寄存器中的值来指定有效的内存空间。然而在访问地址是,一个有符号值将会被加至寄存器中从而指向下一个有效的地址空间,这一操作被默认的进行。例如:

R2 = memw(R3++#4) // R3 contains the effective address
// R3 is then incremented by 4

若使用汇编语言来编写,该增加的值通常从寄存器中获得。请注意偏移量必须为指令数据大小的倍数。
下图列出了自增的范围
Hexagon DSP的十二种寻址模式

循环自增立即数寻址
循环自增立即数寻址与上面讲的寻址方式大致相同,差别在于循环自增立即数寻址通过使用优化的寄存器Mx而不是立即数来保存增值。例如:

R2 = memw(R0++M1) // The effective addr is the value of R0.
// Next, M1 is added to R0 and the result
// is stored in R0.

在使用自增的寄存器是,增加的值是一个有符号的32位数值,该数值被自动加上通用寄存器中。这使得自增立即数寻址有如下两个优点:
 自增数的范围更大
 可*变换的自增数尺寸
自增数的值通常在通用寄存器中进行定义
循环自增寄存器寻址
循环自增寄存器寻址是间接自增寄存器寻址的一个分支,通过这个方式,我们可以通过在环绕模数的形式来访问数据缓冲区。循环寻址在数据流处理中应用的非常普遍。
循环寻址在汇编语言的编写中通常使用:circ(Mx),其中Mx代表着寄存器,该寄存器用于定义循环缓冲区大小。例如:

R0 = memb(R2++#4:circ(M0)) // load from R2 in circ buf specified // by M0 memw(R2++#8:circ(M1)) = R0 // store to R2 in circ buf specified // by M1

循环寻址可通过编写如下元素来设置:
 Mx寄存器的长度值用来代表循环缓冲区的大小。缓冲区可以是4-128kb长
 Mx的K区域一般设置为0
 循环通常开始于寄存器CSx,这个值根据Mx在循环缓冲区设置的开始区域来决定
在循环寻址中,访问内存的过程结束后,通用寄存器中的地址会加上一个立即数,接着被循环缓冲区变换,从而实现对缓冲区的循环实现。
若使用汇编语句来表示,那么相加的值通常定义了通用寄存器中的偏移量。下图列出了循环移位自增寻址的增量范围
Hexagon DSP的十二种寻址模式

为了实现循环缓冲区,必须遵守下列规则:
 起始地址必须对齐本地缓冲元素的访问大小
 ABS(相加)

R4.H = #0 // K = 0
R4.L = #150 // length = 150
M0 = R4
R2 = ##cbuf // start addr = cbuf
CS0 = R2
R0 = memb(R2++#4:circ(M0)) // Load byte from circ buf
// specified by M0/CS0
// inc R2 by 4 after load
// wrap R2 around if >= 150

如下所示的C函数可以用来描述循环加函数的行为

unsigned int
fcircadd(unsigned int pointer, int offset,
unsigned int M_reg, unsigned int CS_reg)
{
unsigned int length;
int new_pointer, start_addr, end_addr;
length = (M_reg&0x01ffff); // lower 17-bits gives buffer size
new_pointer = pointer+offset;
start_addr = CS_reg;
end_addr = CS_reg + lenth;
if (new_pointer >= end_addr) {
new_pointer -= length;
} else if (new_pointer < start_addr) {
new_pointer += length;
}
return (new_pointer);
}

位反转自增寻址
位反转自增寄存器寻址是间接自增寻址的一个分支,这种方式通过使用位反转的地址值来访问数据缓冲区。位反转的地址在FFT以及Viterbi解码中使用的非常广泛。
位反转的32位地址通过如下方式定义:
 低16位通过交换0位以及15位来转换,也就是1位换14位,以此类推。
 高15位不变
位反转寻址在汇编语言中以:brev来表示:例如

R2 = memub(R0++M1:brev) // The address is (R0.H | bitrev(R0.L))
// The orginal R0 (not reversed) is added
// to M1 and written back to R0

寻址的地址初始值必须在位反转的格式中定义,通过硬件反转位反转的值来构建有效内存地址。
一个位反转的缓冲区长度必须是2的n次方,最大为64K字节。
为了支持位反转地址寻址,缓冲区必须在内存中对齐。一个位反转缓冲区在初始时被适宜的对齐至2的n次方。例如:

int bitrev_buf[256] __attribute__((aligned(1024)));

上面所表达的位反转缓冲区被对齐到了1024个字节,因为缓冲区是1024字节而且是2的整数次方。
一个位反转缓冲区的缓冲区地址指针必须被初始化,使得位反转中的16位地址值可以实现位反转。
可以通过如下的值来初始化:

bitreverse(buffer_size_in_bytes / 2)

bitreverse代表着在确保其他值不变的情况下位反转最低位的16位值。
注:为了简化位反转值的初始化过程,位反转缓冲区可以被对齐至64K字节的边界。这样的优势在于可以允许位反转指正初始化至位反转缓冲区的基地址。
因为缓冲区可以以堆栈进行放置,这种方式只能对齐8字节甚至更小,一般不再堆栈中调用。
在位反转内存访问实现后,通用寄存器的值将加上增寄存器的值。
注:Hexagon处理器只对位反转寻址支持寄存器自增,不支持立即数自增。