跳转至

FRET.STK

说明

函数返回出口(Function Exit and Return by Stack)
本指令从栈中加载返回地址至 BARG.BPCN 域,更新栈指针后,从新栈指针指向的内存加载 8 字节数据至连续寄存器组。

本指令用于函数出口的收栈操作(Function Epilogue)。

汇编语法

    FRET.STK [RegDstM ~ RegDstn], sp!, uimm

汇编符号

  • sp!:栈指针寄存器,块内部更新该寄存器。
  • uimm:表示收栈空间大小的立即数(以8字节为单位),该参数编码于uimm[14:3]字段。
  • RegDstM ~ RegDstN:指示出栈起止寄存器,表示R2至R23中一段连续的寄存器。

注意!

当DstBegin的索引大于DstEnd的索引时,出栈寄存器顺序会发生卷绕。具体而言就是先将DstBegin至R23出栈,再将R2至DstEnd出栈。

编码格式

FRET.STK

执行方式

  • 产生指令并push到指令队列:Generate()
  • 转换为十进制数:UInt()

硬件模板块状态机会将该指令展开为以下微指令去执行:

bits(15) immediate = uimm << 3;

if immediate[14:12] != 0 then
    Generate(lui immediate[14:12], ->t);
    Generate(addi t#1, immediate[11:0], ->t);
    Generate(add sp, t#1, ->sp);
else
    Generate(addi sp, immediate[11:0], ->sp);

integer M = UInt(DstBegin);
integer N = UInt(DstEnd);
integer offset = -16;

// 如果DstEnd 编码小于 DstBegin,那么出栈寄存器发生卷绕
if M > N then N += 24;

// 将返回地址设置到BARG的BPCN域
Generate(ldi [sp, -8], ->R[M]);
Generate(setc.tgt R[M]);

foreach (idx from M+1 to N by 1 in dec)
    integer idx = i % 24;
    if idx == 0 || idx == 1 then continue;
    Generate(ldi [sp, offset], ->R[idx]);
    offset -= 8;

汇编示例

出栈寄存器未出现环绕的场景,以块指令 f.ret.stk [ra ~ s5], sp!, 64 为例:

addi sp, 64, ->sp
ldi [sp, -8], ->ra
setc.tgt ra

ldi [sp, -16], ->s0     ; 从栈上load至R11
ldi [sp, -24], ->s1     ; 从栈上load至R12
ldi [sp, -32], ->s2     ; 从栈上load至R13
ldi [sp, -40], ->s3     ; 从栈上load至R14
ldi [sp, -48], ->s4     ; 从栈上load至R15
ldi [sp, -56], ->s5     ; 从栈上load至R16

出栈寄存器出现环绕的场景,以块指令 f.ret.stk [ra ~ a1], sp!, 160 为例:

addi sp, 160, ->sp
ldi [sp, -8], ->ra
setc.tgt ra

ldi [sp, -16], ->s0     ; 从栈上load至R11
ldi [sp, -24], ->s1     ; 从栈上load至R12
ldi [sp, -32], ->s2     ; 从栈上load至R13
ldi [sp, -40], ->s3     ; 从栈上load至R14
ldi [sp, -48], ->s4     ; 从栈上load至R15
ldi [sp, -56], ->s5     ; 从栈上load至R16
ldi [sp, -64], ->s6     ; 从栈上load至R17
ldi [sp, -72], ->s7     ; 从栈上load至R18
ldi [sp, -80], ->s8     ; 从栈上load至R19
ldi [sp, -88], ->x0     ; 从栈上load至R20
ldi [sp, -96], ->x1     ; 从栈上load至R21
ldi [sp, -104], ->x2    ; 从栈上load至R22
ldi [sp, -112], ->x3    ; 从栈上load至R23
ldi [sp, -120], ->a0    ; 从栈上load至R2(出现卷绕)
ldi [sp, -128], ->a1    ; 从栈上load至R3

注意事项

  • 本块指令的跳转类型为调用返回(Return)

块指令展开微指令数计算

该模板块展开的微指令数计算公式为:InstCount = 1(设置返回地址指令数) + cnt1(更新sp寄存器指令数) + cnt2(出栈指令数)

// 更新sp寄存器指令数
integer cnt1 = (uimm > 4088 ? 3 : 1);
// 出栈指令数
integer M = UInt(DstBegin), N = UInt(DstEnd);
integer cnt2 = (M <= N ? (N - M + 1) : (23 - M + N))

备注

此指令属于模板块指令。