查看: 419|回复: 2
收起左侧

RV32I基础整数指令集

[复制链接]

  离线 

  • TA的每日心情
    奋斗
    2021-3-3 12:32
  • 签到天数: 10 天

    [LV.3]

    发表于 2021-3-6 12:09:49 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 皋陶 于 2021-3-6 12:32 编辑

          RV32I是32位基础整数指令集,它支持32位寻址空间,支持字节地址访问,仅支持小端格式(little-endian,高地址高位,低地址地位),寄存器也是32位整数寄存器。

          RV32I指令集的目的是尽量简化硬件的实施设计,所以它只有40条指令(备注,之前是47条指令,在最新的规范中,一些csr指令被放在扩展指令集中)。这40条指令几乎能够模拟其它任何扩展指令(除了A扩展指令,因为原子指令需要硬件支持)。如果用更简单的实现方式,比如对于ECALL和EBREAK指令,调用时候,系统总是自陷(trap),以及用NOP指令模拟Fence指令,则RV32I甚至可以减少到38条指令(备注:在RISC V中,NOP指令是伪代码,其实就是addi, x0,x0,0)。

          实际上要实现机器模式的RiscV特权架构,还需要6条csr指令,之前这些指令都是在RV32I中的,现在被放在扩展指令集 Zicsr中了。所以说要实现一个完整的RiscV系统,至少要实现RV32I+Zicsr指令集。

          在RV32I指令集架构中,包括32个通用目的寄存器,其中x0被预留为常数0,其它31个寄存器(x1-x31)是普通的通用整数寄存器。在RISC-V汇编语言中,每个通用寄存器都有一个对应的ABI名字,也就是说在汇编语言中,x1等价于ra,它们都会汇编成相同的机器码。对于RV32I,通用寄存器是32位的寄存器,xlen=32;对于RV64I,通用寄存器是64位寄存器,xlen=64。

          在Risc-V架构中,要得到当前指令pc(指令在存储器中的位置,instruction program counter),可以通过AUIPC指令,把它读入到一个通用寄存器中。

    寄存器
    ABI名字
    注释
    Saver
    x0
    zero
    Hard-wired zero,常数0
    x1
    ra
    Return address
    caller,调用函数的指令pc
    x2
    sp
    Stack pointer
    callee,被调用的函数指令pc
    x3
    gp
    Global pointer
    x4
    tp
    Thread pointer
    x5
    t0
    Temporary/alternate link register
    caller
    x6
    t1
    Temporaries
    caller
    x7
    t2
    Temporaries
    caller
    x8
    s0/fp
    Saved register/frame pointer
    caller
    x9
    s1
    Saved register
    caller
    x10
    a0
    Function arguments/return values
    caller
    x11
    a1
    Function arguments/return values
    caller
    x12
    a2
    Function arguments
    caller
    x13
    a3
    Function arguments
    caller
    x14
    a4
    Function arguments
    caller
    x15
    a5
    Function arguments
    caller
    x16
    a6
    Function arguments
    caller
    x17
    a7
    Function arguments
    caller
    x18
    s2
    Saved registers
    caller
    x19
    s3
    Saved registers
    caller
    x20
    s4
    Saved registers
    caller
    x21
    s5
    Saved registers
    caller
    x22
    s6
    Saved registers
    caller
    x23
    s7
    Saved registers
    caller
    x24
    s8
    Saved registers
    caller
    x25
    s9
    Saved registers
    caller
    x26
    s10
    Saved registers
    caller
    x27
    s11
    Saved registers
    caller
    x28
    t3
    Temporaries
    caller
    x29
    t4
    Temporaries
    caller
    x30
    t5
    Temporaries
    caller
    x31
    t6
    Temporaries
    caller
    Base指令格式:
          RV32I指令格式包括以下6种,每种指令格式都是固定的32位指令,所以指令在内存中必须4字节对齐。比如一个分支跳转指令,当条件判定是跳转的时候,而目的地址不是4字节对齐,则产生指令地址不对齐异常。无条件跳转指令也是如此,目的地址不是4字节对齐,则产生指令地址不对齐异常。备注:但在实际应用中,很难会产生这种错误,因为在汇编语言中,我们用label作为跳转目的,汇编器会自动帮我们产生字节对齐的偏移地址。

          其中rd表示目的寄存器,rs1是源操作数寄存器1,rs2是源操作数寄存器2。

    国内芯片技术交流-RV32I基础整数指令集risc-v单片机中文社区(1)

          imm表示指令中的立即数,比如imm[11:0],表示一个12位的立即数,它的高20位会符号位扩展,也就是用最左边的位imm[11]来进行扩展。imm[31:12]表示一个32位的立即数,它的低12位会补0。备注: csr指令中的5位立即数不需要符号位扩展。
    下图是各种指令格式扩展后的32位立即数。

    国内芯片技术交流-RV32I基础整数指令集risc-v单片机中文社区(2)

          分支指令(B 类型)的立即数字段在 S 类型的基础上旋转了 1 位。跳转指令(J类型)的直接字段在 U 类型的基础上旋转了 12 位。因此,RISC-V 实际上只有四种基本格式,但我们可以保守地认为它有六种格式。
    RV32I整数指令集

    RV32I整数指令集分为几个种类:

    1.Load和store指令
          RV32I是一个load /store架构,所有的memory访问都是通过load/store指令,其它指令都是在寄存器之间或者寄存器和立即数之间进行运算,比如加法指令,减法指令等等。注意,装入目的寄存器如果为x0,将会产生一个异常。Load/Store指令在memory和寄存器之间传输数据,Load指令编码为I型,store指令编码为S型。计算memory地址时候,imm都会符号扩展成32位,然后和rs1相加,得到memory地址。为了提高性能,load/store指令应该尽量对齐地址,比如lw指令,访问地址应该4字节对齐,lh访问地址应该双字节对齐。根据微架构实现的不同,不对齐地址的访问可能会比较慢,而且地址对齐访问,能够确保是原子操作,不对齐的话为了读取和存储数据正确,还要进行额外的同步操作。

    lb

    lb rd, offset(rs1)   //x[rd] = sext(M[x[rs1] + sext(offset)][7:0])

    字节加载 (Load Byte). I-type, RV32I and RV64I.

    从地址 x[rs1] + sign-extend(offset)读取一个字节,经符号位扩展后写入x[rd]。

    imm(offset)
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    lb
    I
    0
    0
    0
    0
    0
    0
    0
    0
    1
    1
    例子:
    Disassembly of section .text:
    00000000 <.text>:
        0:   00510503                lb      x10,5(x2)
        4:   fec18283                lb      x5,-20(x3)
    注:立即数为补码表示


    lh
    lh rd, offset(rs1)   //x[rd] = sext(M[x[rs1] + sext(offset)][15:0])
    半字加载 (Load Halfword). I-type, RV32I and RV64I.
    从地址 x[rs1] + sign-extend(offset)读取两个字节,经符号位扩展后写入 x[rd]。
    imm(offset)
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    lh
    I
    0
    0
    1
    0
    0
    0
    0
    0
    1
    1

    例子:
    0:   00511503                lh      x10,5(x2)

    lw
    lw rd, offset(rs1)   //x[rd] = sext(M[x[rs1] + sext(offset)][31:0])
    字加载 (Load Word). I-type, RV32I and RV64I.
    从地址 x[rs1] + sign-extend(offset)读取四个字节,写入 x[rd]。对于 RV64I,结果要进行符号位扩展。
    压缩形式: c.lwsp rd, offset; c.lw rd, offset(rs1)
    imm(offset)
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    RV32I
    lw
    I
    0
    1
    0
    0
    0
    0
    0
    0
    1
    1

    例子:
      0:   00512503                lw      x10,5(x2)

    lbu
    lbu rd, offset(rs1)   //x[rd] = M[x[rs1] + sext(offset)][7:0]
    无符号字节加载 (Load Byte, Unsigned). I-type, RV32I and RV64I.
    从地址 x[rs1] + sign-extend(offset)读取一个字节,经零扩展后写入 x[rd]。
    imm(offset)
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    lbu
    I
    1
    0
    0
    0
    0
    0
    0
    0
    1
    1

    例子:
       0:   00514503                lbu     x10,5(x2)

    lhulhu rd, offset(rs1)   //x[rd] = M[x[rs1] + sext(offset)][15:0]
    无符号半字加载 (Load Halfword, Unsigned). I-type, RV32I and RV64I
    .
    从地址 x[rs1] + sign-extend(offset)读取两个字节,经零扩展后写入 x[rd]。

    imm(offset)
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    lhu
    I
    1
    0
    1
    0
    0
    0
    0
    0
    1
    1
    例子:
       0:   00515503                lhu     x10,5(x2)

    sbsb rs2, offset(rs1)   //M[x[rs1] + sext(offset)] = x[rs2][7: 0]
    存字节(Store Byte)
    . S-type, RV32I and RV64I.
    将 x[rs2]的低位字节存入内存地址 x[rs1]+sign-extend(offset)。

    imm(offset)
    imm(offset)
    11
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    0
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    sb
    S
    0
    0
    0
    0
    1
    0
    0
    0
    1
    1
    例子:
       0:   00520123                sb      x5,2(x4) # 0x2

    sh
    sh rs2, offset(rs1)   //M[x[rs1] + sext(offset) = x[rs2][15: 0]
    存半字(Store Halfword). S-type, RV32I and RV64I.
    将 x[rs2]的低位 2 个字节存入内存地址 x[rs1]+sign-extend(offset)。
    imm(offset)
    imm(offset)
    11
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    0
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    sh
    S
    0
    0
    1
    0
    1
    0
    0
    0
    1
    1

    例子:
      4:   00521123                sh      x5,2(x4) # 0x2

    sw
    sw rs2, offset(rs1)   //M[x[rs1] + sext(offset) = x[rs2][31: 0]
    存字(Store Word). S-type, RV32I and RV64I.
    将 x[rs2]的低位 4 个字节存入内存地址 x[rs1]+sign-extend(offset)。
    压缩形式: c.swsp rs2, offset; c.sw rs2, offset(rs1)
    imm(offset)
    imm(offset)
    11
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    0
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    sw
    S
    0
    1
    0
    0
    1
    0
    0
    0
    1
    1

    例子:
    8:   00522123                sw      x5,2(x4) # 0x2

    2.整数计算指令(算术,逻辑指令,比较指令以及移位指令)
          计算指令在寄存器和寄存器之间,或者在寄存器和立即数之间进行算术或逻辑运算。指令格式为I,R,U。
            整数计算指令不会产生异常,但我们可以通过分支指令增加溢出(overflow)检测,比如对于无符号数加法:
    1. add t0, t1, t2;
    2.         bltu t0, t1, overflow; //如果t0<t1,则跳转到溢出处理
    复制代码
    对于有符号数,如果知道符号位,则可以用下面代码:
    1. addi t0, t1, +imm;
    2.         blt t0, t1, overflow; //t0<t1,则跳转到溢出处理,因为imm为正数
    复制代码
    对于通用有符号数加法,可以用下面的指令:
    1. add t0, t1, t2;
    2.         slti t3, t2, 0;  //如果t2<0, t3=1
    3.         slt t4, t0, t1; //如果t0<t1, t4=1
    4.         bne t3, t4, overflow; //如果t3!=t4, 跳转到溢出程序处理
    复制代码
    算术指令:   add
    add rd, rs1, rs2    //x[rd] = x[rs1] + x[rs2]
    把寄存器 x[rs2]加到寄存器 x[rs1]上,结果写入 x[rd]。忽略算术溢出。
    加 (Add). R-type, RV32I and RV64I
    压缩形式: c.add rd, rs2; c.mv rd, rs2
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    add
    R
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    1
    1
    0
    0
    1
    1

    例子:
          0:   00a48433                add     x8,x9,x10
      addi
    addi rd, rs1, immediate    //x[rd] = x[rs1] + sext(immediate)
    加立即数(
    Add Immediate). I-type, RV32I and RV64I.
    把符号位扩展的立即数加到寄存器 x[rs1]上,结果写入 x[rd]。忽略算术溢出。
    压缩形式: c.li rd, imm; c.addi rd, imm; c.addi16sp imm; c.addi4spn rd, imm
    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    addi
    I
    0
    0
    0
    0
    0
    1
    0
    0
    1
    1

    我们可以用addi指令实现move指令, addi rd, rs1, 0 <=>mv rd,rs1 //x[rd]=x[rs1]
    例子:
    0:   01430513                addi    x10,x6,20

        sub
    sub rd, rs1, rs2    //x[rd] = x[rs1] - x[rs2]
    减(Substract). R-type, RV32I and RV64I.
    x[rs1]减去 x[rs2],结果写入 x[rd]。忽略算术溢出。
    压缩形式: c.sub rd, rs2
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    sub
    R
    0
    1
    0
    0
    0
    0
    0
    0
    0
    0
    0
    1
    1
    0
    0
    1
    1
    例子:
       0:   40a48433                sub     x8,x9,x10

       lui
    lui rd, immediate   //x[rd] = sext(immediate[31:12] << 12)
    高位立即数加载 (Load Upper Immediate). U-type, RV32I and RV64I.
    20 位立即数 immediate 左移 12 位, 并将低 12 位置零, 写入 x[rd]中。
    压缩形式: c.lui rd, imm
    imm
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    lui
    U
    0
    1
    1
    0
    1
    1
    1
    例子:
    0:   00003237                lui     x4,0x3
    4:   000141b7                lui     x3,0x14
    8:   000102b7                lui     x5,0x10
    lui     x5,-0x10  注意:立即数不能为负,范围是0..1048575。
    mm.s: Assembler messages:
    mm.s:1: Error: lui expression not in range 0..1048575,


        auipc
    auipc rd, immediate    //x[rd] = pc + sext(immediate[31:12] << 12)
    PC 加立即数 (Add Upper Immediate to PC). U-type, RV32I and RV64I.
    把符号位扩展的 20 位(左移 12 位)立即数加到 pc 上,结果写入 x[rd]。
    imm
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    auipc
    U
    0
    0
    1
    0
    1
    1
    1

    例子:
       0:   0000a297                auipc   x5,0xa
    用 auipc x5,0 我们能得到当前的pc值。

    逻辑指令:   xor
    xor rd, rs1, rs2   //x[rd] = x[rs1] ^ x[rs2]
    异或(Exclusive-OR). R-type, RV32I and RV64I.
    x[rs1]和 x[rs2]按位异或,结果写入 x[rd]。
    压缩形式: c.xor rd, rs2
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    xor
    R
    0
    0
    0
    0
    0
    0
    0
    1
    0
    0
    0
    1
    1
    0
    0
    1
    1

    例子:
       c:   00a4c433                xor     x8,x9,x10

    xori
    xori rd, rs1, immediate   //x[rd] = x[rs1] ^ sext(immediate)
    立即数异或(Exclusive-OR Immediate). I-type, RV32I and RV64I.
    x[rs1]和有符号扩展的 immediate 按位异或,结果写入 x[rd]。
    压缩形式: c.xor rd, rs2
    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    xori
    I
    1
    0
    0
    0
    0
    1
    0
    0
    1
    1


    例子:
       0:   00224293                xori    x5,x4,2

    or
    or rd, rs1, rs2    //x[rd] = x[rs1] | x[rs2]
    取或(OR). R-type, RV32I and RV64I.
    把寄存器 x[rs1]和寄存器 x[rs2]按位取或,结果写入 x[rd]。
    压缩形式: c.or rd, rs2
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    or
    R
    0
    0
    0
    0
    0
    0
    0
    1
    1
    0
    0
    1
    1
    0
    0
    1
    1

    例子:
      18:   00a4e433                or      x8,x9,x10

    ori
    ori rd, rs1, immediate   //x[rd] = x[rs1] | sext(immediate)
    立即数取或(OR Immediate). R-type, RV32I and RV64I.
    把寄存器 x[rs1]和有符号扩展的立即数 immediate 按位取或,结果写入 x[rd]。
    压缩形式: c.or rd, rs2
    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    ori
    I
    1
    1
    0
    0
    0
    1
    0
    0
    1
    1


    例子:
       0:   00226293                ori     x5,x4,2

    and
    and rd, rs1, rs2   //x[rd] = x[rs1] & x[rs2]
    与 (And). R-type, RV32I and RV64I.
    将寄存器 x[rs1]和寄存器 x[rs2]位与的结果写入 x[rd]。
    压缩形式: c.and rd, rs2
    func7
    rs2
    rs1
    func3
    rd
    opcode
    and
    R
    0
    0
    0
    0
    0
    0
    0
    1
    1
    1
    0
    1
    1
    0
    0
    1
    1

    例子:
      1c:   00a4f433                and     x8,x9,x10

    andi
    andi rd, rs1, immediate  //x[rd] = x[rs1] & sext(immediate)
    与立即数 (And Immediate). I-type, RV32I and RV64I.
    把符号位扩展的立即数和寄存器 x[rs1]上的值进行位与,结果写入 x[rd]。
    压缩形式: c.andi rd, imm
    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    andi
    I
    1
    1
    1
    0
    0
    1
    0
    0
    1
    1

    例子:
      0:   00227293                andi    x5,x4,2

    移位指令:sll
    sll rd, rs1, rs2   //x[rd] = x[rs1] ≪ x[rs2]
    逻辑左移(Shift Left Logical). R-type, RV32I and RV64I.
    把寄存器 x[rs1]左移 x[rs2]位,空出的位置填入 0,结果写入 x[rd]。 x[rs2]的低 5 位(如果是RV64I 则是低 6 位)代表移动位数,其高位则被忽略。
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    sll
    R
    0
    0
    0
    0
    0
    0
    0
    0
    0
    1
    0
    1
    1
    0
    0
    1
    1

    例子:
       0:   00a49433                sll     x8,x9,x10

    slli
    slli rd, rs1, shamt   //x[rd] = x[rs1] ≪ shamt
    立即数逻辑左移(Shift Left Logical Immediate). I-type, RV32I and RV64I.
    把寄存器 x[rs1]左移 shamt位,空出的位置填入 0,结果写入 x[rd]。对于 RV32I,仅当 shamt[5]=0
    时,指令才是有效的。
    压缩形式: c.slli rd, shamt
    shamt
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    slli
    I
    0
    0
    0
    0
    0
    0
    0
    0
    1
    0
    0
    1
    0
    0
    1
    1

    例子:
       0:   00511513                slli    x10,x2,0x5

    srl
    srl rd, rs1, rs2  //x[rd] = (x[rs1] ≫u x[rs2])
    逻辑右移(Shift Right Logical). R-type, RV32I and RV64I.
    把寄存器 x[rs1]右移 x[rs2]位,空出的位置填入 0,结果写入 x[rd]。 x[rs2]的低 5 位(如果是 RV64I 则是低 6 位)代表移动位数,其高位则被忽略。
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    srl
    R
    0
    0
    0
    0
    0
    0
    0
    1
    0
    1
    0
    1
    1
    0
    0
    1
    1
    例子:
      10:   00a4d433                srl     x8,x9,x10

    srli
    srli rd, rs1, shamt   //x[rd] = (x[rs1] ≫u shamt)
    立即数逻辑右移(Shift Right Logical Immediate). I-type, RV32I and RV64I.
    把寄存器 x[rs1]右移 shamt位,空出的位置填入 0,结果写入 x[rd]。对于 RV32I,仅当 shamt[5]=0 时,指令才是有效的。
    压缩形式: c.srli rd, shamt
    shamt
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    srli
    I
    0
    0
    0
    0
    0
    0
    1
    0
    1
    0
    0
    1
    0
    0
    1
    1
    例子:
       0:   00515513                srli    x10,x2,0x5

    sra
    sra rd, rs1, rs2    //x[rd] = (x[rs1] ≫s x[rs2])
    算术右移(Shift Right Arithmetic). R-type, RV32I and RV64I.
    把寄存器 x[rs1]右移 x[rs2]位,空位用 x[rs1]的最高位填充,结果写入 x[rd]。 x[rs2]的低 5 位 (如果是 RV64I 则是低 6 位)为移动位数,高位则被忽略。
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    sra
    R
    0
    1
    0
    0
    0
    0
    0
    1
    0
    1
    0
    1
    1
    0
    0
    1
    1
    例子:
      14:   40a4d433                sra     x8,x9,x10

    srai
    srai rd, rs1, shamt    //x[rd] = (x[rs1] ≫s shamt)
    立即数算术右移(Shift Right Arithmetic Immediate). I-type, RV32I and RV64I.
    把寄存器 x[rs1]右移 shamt 位,空位用 x[rs1]的最高位填充,结果写入 x[rd]。对于 RV32I, 仅当 shamt[5]=0 时指令有效。
    压缩形式: c.srai rd, shamt
    shamt
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    srai
    I
    0
    1
    0
    0
    0
    0
    1
    0
    1
    0
    0
    1
    0
    0
    1
    1
    例子:
       0:   40515513                srai    x10,x2,0x5

    比较指令:
    slt
    slt rd, rs1, rs2    //x[rd] = (x[rs1] <s x[rs2])
    小于则置位(Set if Less Than). R-type, RV32I and RV64I.
    比较 x[rs1]和 x[rs2]中的数,如果 x[rs1]更小,向 x[rd]写入 1,否则写入 0。
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    slt
    R
    0
    0
    0
    0
    0
    0
    0
    0
    1
    0
    0
    1
    1
    0
    0
    1
    1
    例子:
       4:   00a4a433                slt     x8,x9,x10

    slti
    slti rd, rs1, immediate    //x[rd] = (x[rs1] <s sext(immediate))
    小于立即数则置位(Set if Less Than Immediate). I-type, RV32I and RV64I.
    比较 x[rs1]和有符号扩展的 immediate,如果 x[rs1]更小,向 x[rd]写入 1,否则写入 0。
    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    slti
    I
    0
    1
    0
    0
    0
    1
    0
    0
    1
    1
    例子:
       0:   00222293                slti    x5,x4,2

    sltu
    sltu rd, rs1, rs2     //x[rd] = (x[rs1] <u x[rs2])
    无符号小于则置位(Set if Less Than, Unsigned). R-type, RV32I and RV64I.
    比较 x[rs1]和 x[rs2],比较时视为无符号数。如果 x[rs1]更小,向 x[rd]写入 1,否则写入 0。
    func7
    rs2
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    sltu
    R
    0
    0
    0
    0
    0
    0
    0
    0
    1
    1
    0
    1
    1
    0
    0
    1
    1
    例子:
       8:   00a4b433                sltu    x8,x9,x10

    sltiu
    sltiu rd, rs1, immediate   //x[rd] = (x[rs1] <u sext(immediate))
    无符号小于立即数则置位(Set if Less Than Immediate, Unsigned). I-type, RV32I and RV64I.
    比较 x[rs1]和有符号扩展的 immediate,比较时视为无符号数。如果 x[rs1]更小,向 x[rd]写入 1,否则写入 0
    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    sltiu
    I
    0
    1
    1
    0
    0
    1
    0
    0
    1
    1
    例子:
    0:   00223293                sltiu   x5,x4,2



    3. 控制指令,包括无条件跳转指令和条件跳转指令beq
    beq rs1, rs2, offset   //if (rs1 == rs2) pc += sext(offset)
    相等时分支跳转 (Branch if Equal). B-type, RV32I and RV64I.
    若寄存器 x[rs1]和寄存器 x[rs2]的值相等,把 pc 的值设为当前值加上符号位扩展的偏移 offset。
    压缩形式: c.beqz rs1, offset

     
     
    imm
     
    imm
     
     
     
    12
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    11
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    beq
    B
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    0
    0
    0
     
     
     
     
     
    1
    1
    0
    0
    0
    1
    1

    例子:
    00000000 <label-0x8>:
        0:   00628463                beq     x5,x6,8 <label>
        4:   00a48433                add     x8,x9,x10
    00000008 <label>:
        8:   00d605b3                add     x11,x12,x13

    bne
    bne rs1, rs2, offset   //if (rs1 ≠ rs2) pc += sext(offset)
    不相等时分支跳转 (Branch if Not Equal). B-type, RV32I and RV64I.
    若寄存器 x[rs1]和寄存器 x[rs2]的值不相等,把 pc 的值设为当前值加上符号位扩展的偏移offset。
    压缩形式: c.bnez rs1, offset
     
     
    imm
     
    imm
     
     
     
    12
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    11
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    bne
    B
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    0
    0
    1
     
     
     
     
     
    1
    1
    0
    0
    0
    1
    1


    例子:
    00000000 <label-0x8>:
        0:   00629463                bne     x5,x6,8 <label>
        4:   00a48433                add     x8,x9,x10
    00000008 <label>:
        8:   00d605b3                add     x11,x12,x13

    blt
    blt rs1, rs2, offset    //if (rs1 <s rs2) pc += sext(offset)
    小于时分支跳转 (Branch if Less  Than). B-type, RV32I and RV64I.
    若寄存器 x[rs1]的值小于寄存器 x[rs2]的值(均视为二进制补码),把 pc 的值设为当前值加上符号位扩展的偏移 offset。
     
     
    imm
     
    imm
     
     
     
    12
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    11
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    blt
    B
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    1
    0
    0
     
     
     
     
     
    1
    1
    0
    0
    0
    1
    1

    例子:
    00000000 <label-0x8>:
        0:   0062c463                blt     x5,x6,8 <label>
        4:   00a48433                add     x8,x9,x10
    00000008 <label>:
        8:   00d605b3                add     x11,x12,x13


    bge

    bge rs1, rs2, offset  //if (rs1 ≥s rs2) pc += sext(offset)

    大于等于时分支 跳转(Branch if Greater Than or Equal). B-type, RV32I and RV64I.

    若寄存器 x[rs1]的值大于等于寄存器 x[rs2]的值(均视为二进制补码),把 pc 的值设为当前值加上符号位扩展的偏移 offset。

     
     
    imm
     
    imm
     
     
     
    12
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    11
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    bge
    B
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    1
    0
    1
     
     
     
     
     
    1
    1
    0
    0
    0
    1
    1
    例子:
    00000000 <label-0x8>:
        0:   0062d463                bge     x5,x6,8 <label>
        4:   00a48433                add     x8,x9,x10
    00000008 <label>:
        8:   00d605b3                add     x11,x12,x13

    bltu
    bltu rs1, rs2, offset   //if (rs1 <u rs2) pc += sext(offset)
    无符号小于时分支跳转 (Branch if Less  Than, Unsigned). B-type, RV32I and RV64I.
    若寄存器 x[rs1]的值小于寄存器 x[rs2]的值(均视为无符号数),把 pc 的值设为当前值加上
    符号位扩展的偏移 offset。
     
     
    imm
     
    imm
     
     
     
    12
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    11
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    bltu
    B
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    1
    1
    0
     
     
     
     
     
    1
    1
    0
    0
    0
    1
    1
    例子:
    00000000 <label-0x8>:
        0:   0062e463                bltu    x5,x6,8 <label>
        4:   00a48433                add     x8,x9,x10
    00000008 <label>:
        8:   00d605b3                add     x11,x12,x13

    bgeu
    bgeu rs1, rs2, offset   //if (rs1 ≥u rs2) pc += sext(offset)
    无符号大于等于时分支跳转 (Branch if Greater Than or Equal, Unsigned). B-type, RV32I and RV64I.
    若寄存器 x[rs1]的值大于等于寄存器 x[rs2]的值(均视为无符号数),把 pc 的值设为当前值加上符号位扩展的偏移 offset。
     
     
    imm
     
    imm
     
     
     
    12
    10
    9
    8
    7
    6
    5
    rs2
    rs1
    func3
    4
    3
    2
    1
    11
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    bgeu
    B
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    1
    1
    1
     
     
     
     
     
    1
    1
    0
    0
    0
    1
    1
    例子:
    00000000 <label-0x8>:
        0:   0062f463                bgeu    x5,x6,8 <label>
        4:   00a48433                add     x8,x9,x10
    00000008 <label>:
        8:   00d605b3                add     x11,x12,x13

    jal
    jal rd, offset  //x[rd] = pc+4; pc += sext(offset)

    跳转并链接 (Jump and  Link). J-type, RV32I and RV64I.

    把下一条指令的地址(pc+4)保存到目的寄存器,然后把 pc 设置为当前值加上符号位扩展的offset。rd 默认为 x1。

    压缩形式: c.j offset; c.jal offset

    imm
    20
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    11
    19
    18
    17
    16
    15
    14
    13
    12
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    jal
    J
    1
    1
    0
    1
    1
    1
    1
    例子:
    00000000 <label-0x1c>:
        0:   01430513                addi    x10,x6,20
        4:   01430593                addi    x11,x6,20
        8:   01430513                addi    x10,x6,20
        c:   01430513                addi    x10,x6,20
       10:   00c000ef                jal     x1,1c <label>
       14:   01430613                addi    x12,x6,20
       18:   01430613                addi    x12,x6,20
    0000001c <label>:
       1c:   01430613                addi    x12,x6,20
       20:   01430613                addi    x12,x6,20
       24:   01430613                addi    x12,x6,20

    注意:汇编和spec有点不一样,汇编里面jal的立即数是绝对地址,但指令编码是对的,偏移了12个字节,所以imm[3:1]=110,imm[0]默认为0。

    00000004 <label>:
        4:   01430593                addi    x11,x6,20
        8:   01430513                addi    x10,x6,20
        c:   01430513                addi    x10,x6,20
       10:   ff5ff0ef                jal     x1,4 <label>
       14:   01430613                addi    x12,x6,20
       18:   01430613                addi    x12,x6,20
    偏移 为-12,补码表示

    jalr
    jalr rd, offset(rs1)     // t =pc+4; pc=(x[rs1]+sext(offset))&~1; x[rd]=t

    跳转并寄存器链接 (Jump and Link Register). I-type, RV32I and RV64I.

    把 pc 设置为 x[rs1] + sign-extend(offset),把计算出的地址的最低有效位设为 0,并将原 pc+4的值写入 f[rd]。 rd 默认为 x1。

    压缩形式: c.jr rs1; c.jalr rs1

    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    jalr
    I
    0
    0
    0
    1
    1
    0
    0
    1
    1
    1
    例子:
    00000000 <label-0x4>:
        0:   01430513                addi    x10,x6,20
    00000004 <label>:
        4:   01430593                addi    x11,x6,20
        8:   01430513                addi    x10,x6,20
        c:   01430513                addi    x10,x6,20
       10:   ffc082e7                jalr    x5,-4(x1)
       14:   01430613                addi    x12,x6,20
       18:   01430613                addi    x12,x6,20

    00000000 <label-0x4>:
        0:   01430513                addi    x10,x6,20
    00000004 <label>:
        4:   01430593                addi    x11,x6,20
        8:   01430513                addi    x10,x6,20
        c:   01430513                addi    x10,x6,20
       10:   004082e7                jalr    x5,4(x1)
       14:   01430613                addi    x12,x6,20
       18:   01430613                addi    x12,x6,20




    4. 同步指令fence
    fence pred, succ     //Fence(pred, succ)

    同步内存和 I/O(Fence Memory and I/O). I-type, RV32I and RV64I.

    在后续指令中的内存和 I/O 访问对外部(例如其他线程)可见之前,使这条指令之前的内存及 I/O 访问对外部可见。比特中的第 3,2,1 和 0 位分别对应于设备输入,设备输出,内存读写。例如 fence r, rw,将前面读取与后面的读取和写入排序,使用 pred = 0010 和 succ = 0011进行编码。如果省略了参数,则表示 fence iorw, iorw,即对所有访存请求进行排序

    pred
    succ
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    fence
    I
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    1
    1
    1
    1
    例子:
      0:   0ff0000f                fence   iorw,iorw



    Risc-V在多个hart(硬件线程)之间使用的是松散一致性模型,所以需要存储器fence指令。

    fence指令能够保证存储器访问的执行顺序。在fence指令之前的所有存储器访问指令,比该fence之后的所有数据存储器访问指令先执行。

    Risc-V架构将数据存储器的地址空间分为设备IO(device IO)和普通存储器空间,因此其读写访问分为四种类型:

    I:设备读(device-input)
    O:设备写(device-ouput)
    R:存储器读(memory-reads)
    W:存储器写(memory-writes)

    PI/PO/PR/PW,分别表示fence指令之前的四种读写访问类型,SI/SO/SR/SW分别表示fence指令之后的四种读写访问类型。

    国内芯片技术交流-RV32I基础整数指令集risc-v单片机中文社区(3)


    6.环境调用和断点指令


    这两条指令能够产生环境调用异常和生成断点异常,产生异常时候,当前指令的pc值被写入mepc寄存器。
    这两条指令在调试代码时候有用。

    ecall
    ecall     //RaiseException(EnvironmentCall)
    环境调用 (Environment Call). I-type, RV32I and RV64I.
    通过引发环境调用异常来请求执行环境。
    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    ecall
    I
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    1
    1
    1
    0
    0
    1
    1

    例子:
       0:   00000073                ecall

    ebreak
    Ebreak     //RaiseException(Breakpoint)
    环境断点 (Environment Breakpoint). I-type, RV32I and RV64I.
    通过抛出断点异常的方式请求调试器
    imm
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    rs1
    func3
    rd
    opcode
    name
    type
    31
    30
    29
    28
    27
    26
    25
    24
    23
    22
    21
    20
    19
    18
    17
    16
    15
    14
    13
    12
    11
    10
    9
    8
    7
    6
    5
    4
    3
    2
    1
    0
    ebreak
    I
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    1
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    0
    1
    1
    1
    0
    0
    1
    1

    例子:
       0:   00100073                ebreak








    上一篇:Zifencei扩展
    下一篇:RV64I基础整数指令集
    题主优质好文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    点评回复

    使用道具 举报

    RISC-V隐身侠  发表于 2021-6-25 06:57:14

    facebook spy tool

    国内芯片技术交流-RV32I基础整数指令集risc-v单片机中文社区(4)

    FB friends spy is a facebook windows application that offers to its user’s information about their friends they cannot find in there profiles:
    1. Online presence information (offline/online) even if you are in offline chat mode.
    2. People most interested by them.
    3. People most interacting with them(on comments not messages , spying on messages is illegal and forbidden by facebook, so it is impossible to do, thank you for your understanding).
    4. latest Facebook statuses
    5. Places visited.
    6. Events attending or already participated in
    FB friend's spy will ask you for permissions to offer you the information you want, this information will and still be used only by you, it will not be used by anyone else.
    FB friend’s spy uses Facebook SDK to connect to Facebook, so users don’t have to worry about their private or secret information.


    国内芯片技术交流-RV32I基础整数指令集risc-v单片机中文社区(5)
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复 支持 反对

    使用道具

      离线 

  • TA的每日心情
    飞起
    2021-11-22 18:36
  • 签到天数: 31 天

    [LV.5]

    发表于 2021-10-22 07:34:15 | 显示全部楼层
    学习了~~
    全球首家只专注于RISC-V单片机行业应用的中文网站
    点评回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条




    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2021-12-8 23:56 , Processed in 4.330590 second(s), 60 queries .

    快速回复 返回顶部 返回列表