常量值和立即数¶
灵犀指令集的微指令的编码长度为16/32/48/64bit。在灵犀指令集中,对于32位的常量值和立即数拆分成高20bit和低12bit两部分,能够将这些常量值和立即数编码到操作码内,或者使用64bit的指令加载立即数。如果是更大位宽的数值,则需要进一步结合ALU指令进行数据的拼接。下面主要介绍针对32/64bit的常量和立即数的指令表达。
用lui或者addtpc指令编码高20bit的数值, 用addi或者subi指令编码低12bit的数值。使用常量值和立即数的取值操作来告诉汇编获取相应值。
立即数:
if (0 <= imm <= 4095)
addi zero,imm, ->t
else if (-4095 <= imm < 0)
subi zero,-imm, ->t
else if (isInt<32>(imm))
lui (imm & 0xffffff000), ->t
addi t#1,(imm & 0x00000fff), ->t
/* 或者使用一条64bit指令 */
l.addli zero,imm, ->t
else
subi zero, 1, ->t /* 需要进行立即数拼接,如表达0xffffffff */
zext.w t#1, ->t
例如将一个0x3fa80赋值到T寄存器,你需要写成:
或者使用常量值和立即数的取值操作获得立即数的高20bit,低12bit。常量值:变量的地址,在汇编编程时无法确定,但是在生成最终二进制的时候可以确定,并且这部分地址被编码在指令操作码中,不会变化,因此称之为常量值。
if (使用符号绝对地址)
lui %hi(symbol), ->t
addi t#1,%lo(symbol), ->t
else if (使用符号相对当前TPC的相对地址)
if (相对地址isInt<32>)
label:
addtpc %tpcrel_hi(symbol), ->t /* 获得symbol的地址相对于当前微指令tpc的偏移值,高20位编码 */
addi t#1,%tpcrel_lo(label), ->t /* 获得symbol的地址相对于微指令addtpc的地址(等于标签label的地址)的偏移值,低12位编码 */
else
label:
addtpc %got_tpcrel_hi(symbol), ->t /* 获得symbol的GOT表的地址相对于当前微指令tpc的偏移值,高20位编码 */
addi t#1, %tpcrel_lo(label), ->t /* 获得symbol的GOT表的地址相对于微指令addtpc的地址(等于标签label的地址)的偏移值,低12位编码 */
else if (对于线程Local的变量,使用符号相对于TP(线程寄存器)的相对地址)
if(TLS变量的访问,当前仅支持Local Exec的模式)
lui %tprel_hi(symbol), ->t
ssrget 0x0010, ->t
add t#1,t#2, ->t
addi t#1, %tprel_lo(symbol), ->t
else if (对于全局变量,使用符号相对于GP(全局寄存器)的相对地址)
if (全局变量的访问)
lui %gprel_hi(symbol), ->t
ssrget 0x0011, ->t
add t#1, t#2, ->t
addi t#1, %gprel_lo(symbol), ->t
例如想要访问一个TLS变量errno,我需要先拿到errno变量相对TP(线程寄存器)的相对地址