#loongarch架构介绍#[一]基础指令 原创 精华

深开鸿
发布于 2022-12-13 14:55
浏览
13收藏

作者:蒋卫峰 李涛

前言

最近龙芯中科宣布,龙芯2K0500开发板已与OpenHarmony完成了适配验证,LoongArch平台实现初步支持OpenHarmony。本系列文章将对loongarch架构进行介绍。

龙芯架构LoongArch是龙芯中科公司自主设计的一种精简指令集计算机(RISC)风格的指令系统架构。其分为32位和64位两个版本,分别称为LA32架构和LA64架构。本文主要对其中的基础部分进行介绍。本文中的主要信息来源于龙芯目前公开的资料。

1. 指令编码格式

下图为龙芯架构的典型指令编码格式,大部分指令格式都符合这些格式:

#loongarch架构介绍#[一]基础指令-鸿蒙开发者社区

上图中解释:

  • 指令长度固定为32位,无论是LA32还是LA64

  • 上图中共有2R-type、3R-type、2RI8-type等9种编码格式,其中R表示寄存器,I表示立即数。如2RI8-type表示指令格式中除了操作码opcode外,还指定了2个寄存器和一个8位的立即数。

2. 指令汇编格式

loongarch的指令汇编格式主要包括指令名和操作数这两部分,其中指令名格式比较特别。loongarch中指令名可以有前缀和后缀字母,前缀字母有:

  • V:128位向量指令

  • XV:256位向量指令

  • F:非向量浮点指令

  • VF:128位向量浮点指令

  • XVF:256位向量浮点指令

后缀字母有:

  • 对于整数类型指令:.B、.H、.W、.D、.BU、.HU、.WU、.DU分别表示有符号字节、有符号半字、有符号字、有符号双字、无符号字节、无符号半字、无符号字、无符号双字。其中双字仅存在于LA64

  • 对于浮点类型指令:.H、.S、.D、.W、.L、.WU、.LU分别表示半精度、单精度、双精度的浮点数,以及有符号字、有符号双字、无符号字、无符号双字的整数。其中双字仅存在于LA64

举例如下:

  • add.w    rd, rj, rk: 表示寄存器rj和rk相加,结果写入rd。无前缀,后缀.w表示操作数据的位数为32位。

  • fadd.s fd, fj, fk:表示浮点寄存器fj和fk相加,结果写入fd。前缀为f,表示为非向量浮点运算指令。后缀为.s,表示操作数据为单精度浮点数。

  • mulw.d.wu rd, rj, rk:表示寄存器rj和rk相乘,结果写入rd。无前缀。该指令有两个后缀,.d表示rd中结果为双精度浮点数,.wu表示rj和rk中数据为无符号32位整数。

3. 基础指令介绍

3.1 整数运算类

loongarch中有32个通用寄存器,LA32和LA64中分别为32位和64位长度。loongarch中可用这些寄存器执行整数类的指令。

loongarch支持基本的整数运算,有:

  • 加减乘除的add、sub、mul、div等指令。

    addi.w rd, rj, si12表示将寄存器rj和有符号立即数si12进行32位加法运算,结果写入rd。

  • 逻辑移位、算术移位的sll、srl、sra、rotr等指令。

    srl.w rd, rj, rk表示将寄存器rj作逻辑右移rk位,移位结果符号扩展写入寄存器rd。

  • 与或非等操作的and、or、nor、xor、andi、ori等指令。

    and rd, rj, rk表示将寄存器rj和rk作位与运算,结果写入rd。

  • slt、sltu、slti、sltui指令用于小于比较。

    • slt rd, rj, rk表示将寄存器rj和rk视为有符号整数作小于比较,将结果写入rd。

    • sltu rd, rj, rk表示将寄存器rj和rk视为无符号整数作小于比较,将结果写入rd

  • lu12i.w、lu32i.d等指令用于立即数连接。

    lu12i.w rd, si20表示将20位立即数si20最低位连接上12位的0,然后符合扩展后写入rd。

  • 一些位操作指令,有clo、clz、ctz等指令、用于符号扩展的ext指令等。

    • ext.w.b rd, rj表示将rj中低8位数据进行符号扩展后写入rd。

    • clz.w rd, rj表示从第31位开始计数寄存器rj中连续0的个数,结果写入rd。

3.2 浮点运算类

loongarch中有32个浮点寄存器,在LA32和LA64中均为64位。loongarch中可用这些寄存器进行浮点类指令。

loongarch中支持基本的浮点运算,有:

  • 加减乘除相关的fadd、fsub、fmul、fdiv、fmadd、fnmsub等指令。

    • fadd.s fd, fj, fk表示将浮点寄存器fj和fk进行单精度加法运算,结果写入fd。

    • fmsub.d fd, fj, fk, fa表示将浮点寄存器fj和fk进行双精度乘法运算,然后再与fa进行双精度减法运算,结果写入fd。

  • 浮点比较运算相关的fcmp.cond指令。其中.cond可以为多种比较含义的助记符。

    fcmp.ceq.s cc, fj, fk 表示进行相等比较。

  • 浮点转换类的fcvt、ffint、frint等指令。

    • fcvt.s.d fd, fj表示将浮点寄存器fj中的双精度浮点数转换为单精度,并写入fd。

    • ftintrne.w.s fd, fj表示将浮点寄存器fj中的单精度浮点数转换为32位整数写入到fd,并采用“向最近的偶数舍入”。

  • 浮点搬运类型指令,包括fmov、fsel、movgr2fr等指令。

    • fsel fd, fj, fk, ca表示如果条件标志寄存器ca的值为0,则将浮点寄存器fj写入fd,否则将fk写入fd。

    • movgr2fr.w fd, rj表示将rj的低32位写入浮点寄存器fj的低32位。

  • 一些特殊浮点运算指令,有取最小/最大值运算的fmax、fmin、fmaxa、fmina指令、取绝对值的fabs指令、取反的fneg指令、开方和倒数运算相关的fsqrt和frecip等指令,等等。

    fmaxa.s fd, fj, fk表示fd中写入浮点寄存器fj、fk中绝对值的较大者。

3.3 访存指令

和一般RISC一样,loongarch中通过load/store类指令进行访存,有:

  • ld/st指令。

    • ld.b rd, rj, si12表示将rj+有符号立即数si12作为虚拟地址,从该地址取出一个字节数据写入rd。

    • st.w rd, rj, si12表示将rj+有符号立即数si12作为虚拟地址,将rd低32位数据写入该地址。

  • ldx/stx指令。相比ld/st指令,区别是虚拟地址表示不同:

    ldx.b rd, rj, rk表示将rj+rk作为虚拟地址,从该地址取出一个字节数据写入rd。

  • ldptr/stptr指令。相比ld/st指令,区别是立即数表示不同,即立即数的最大位数不同以及其表示的偏移以4字节对齐。

    stptr.w rd, rj, si14表示将rj+有符号立即数si14*4作为虚拟地址,从该地址取出32位数据写入rd。

  • ldgt/stgt、ldle/stle等边界检查访存指令。

    ldgt.b rd, rj, rk表示将rj作为虚拟地址,如果rj大于rk,则从该地址中取出一个字节数据到rd。否则触发异常。

  • 浮点访存指令,包括fld/fst、fldx/fstx、fldgt/fstgt指令等。与前面指令含义基本一致,只不过是用浮点寄存器作为目标寄存器。

    fld.s fd, rj, si12表示将rj+有符号立即数si12作为虚拟地址,从该地址取出一个单精度浮点数数据写入fd。

3.4 转移指令

下面对loongarch中的转移指令进行介绍:

  • 无条件跳转指令b。

    b offs26表示无条件跳转到地址pc+offs26*4,其中offs26为26位的立即数偏移量,且4字节对齐。

  • 无条件跳转指令jirl。和b的区别是,会将pc+4的值进行保存。

    jirl rd, rj, offs16表示无条件跳转到地址pc+offs16*4,然后将pc+4写入rd。其中offs16为16位的立即数偏移量,且4字节对齐。

  • 无条件跳转指令bl。和jirl的区别是,pc+4的值固定保存在r1中。r1别名ra,一般用作保存返回地址。

    bl offs26表示无条件跳转到地址pc+offs26*4,然后将pc+4写入r1。其中offs26为26位的立即数偏移量,且4字节对齐。

  • 条件转移指令beq、bne、blt等。

    beq rj, rd, offs16表示当rj和rd相等时才跳转到地址pc+offs16*4。

3.5 一些补充的基础指令

在阅读linux上loongarch架构相关代码的时候,遇到了一些loongarch资料中没有写出来的指令。本小节中将这些指令列出,其中指令的含义是根据上下文推测出来的。

  • move:如move rd, rj将rj中值复制到rd
  • li:如li.w rd, 1将rd中值置为1
  • la:如la.abs rd, label将label对应地址赋值给rd
  • jr:如jr ra跳转到ra中地址,可能会有一些额外的操作

4. 汇编案例说明

#loongarch架构介绍#[一]基础指令-鸿蒙开发者社区

上图中描述了loongarch中寄存器的使用约定,与其他的架构其实大同小异。有栈指针寄存器,有通用和浮点的传参寄存器,有返回地址寄存器等。下面结合代码进行说明。

以下为一段c语言代码:

...
extern long
nested(long a, long b, long c, long d, 
    long e, long f, long g, long h, long i);

long normal(void) {
    return nested(1, 2, 3, 4, 5, 6, 7, 8, 9);
}

对应loongarch汇编如下:

normal:
    // 分配栈帧
    addi.d    $sp, $sp, -32   
    
    // 传参9,传参寄存器不够,储存在栈上
    addi.w    $t0, $zero, 9
    stptr.d   $t0, $sp, 0
    
    // 传参8-1,使用传出寄存器a7-a0
    addi.w    $a7, $zero, 8
    addi.w    $a6, $zero, 7
    addi.w    $a5, $zero, 6
    addi.w    $a4, $zero, 5
    addi.w    $a3, $zero, 4
    addi.w    $a2, $zero, 3
    addi.w    $a1, $zero, 2
    addi.w    $a0, $zero, 1
    
    // 将返回地址保存到栈上
    st.d      $ra, $sp, 24
    
    // 调用nested函数
    bl        %plt(nested)
    
    // 恢复返回地址到ra
    ld.d      $ra, $sp, 24

    // 恢复栈帧
    addi.d    $sp, $sp, 32
    
    // 函数返回
    jr        $ra

loongarch的栈帧可用下图表示:

#loongarch架构介绍#[一]基础指令-鸿蒙开发者社区

总结

本文介绍了loongarch架构中的一些基础指令,如整数和浮点运算指令、转移指令、访存指令,并结合案例对loongarch汇编语言的写法进行了说明。下一篇文章将会介绍loongarch中的原子指令、栅障指令,及其用法。

更多原创内容请关注:深开鸿技术团队

入门到精通、技巧到案例,系统化分享OpenHarmony开发技术,欢迎投稿和订阅,让我们一起携手前行共建生态。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-12-20 10:03:29修改
13
收藏 13
回复
举报
8条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

期待loongarch与OpenHarmony碰出的火花

1
回复
2022-12-13 16:18:28
青舟321
青舟321

都是国产,必须支持!

1
回复
2022-12-14 10:30:49
皮皮虾233
皮皮虾233

没了解过汇编,正好学习下

1
回复
2022-12-14 18:19:48
只看看不说话
只看看不说话

龙芯的芯片现在是啥水平?

1
回复
2022-12-15 18:10:32
诺舒华吃西瓜
诺舒华吃西瓜

很全的指令整理,先收藏了

1
回复
2022-12-16 10:59:52
鸿开狂人
鸿开狂人 回复了 只看看不说话
龙芯的芯片现在是啥水平?

据我所了解,新的cpu体系架构是自己设计了。

2
回复
2022-12-19 10:35:06
带带小老弟
带带小老弟

使用国产的芯片适配会更方便吗?

1
回复
2022-12-19 10:51:32
FlashinMiami
FlashinMiami 回复了 带带小老弟
使用国产的芯片适配会更方便吗?

离得近应该会方便些吧

1
回复
2022-12-19 14:13:15
回复
    相关推荐