跳转至

Instructions: Language of the Computer

约 2804 个字 5 行代码 预计阅读时间 10 分钟

Thanks

本节笔记中使用到的RISC-V指令表格样式来自@TonyCrane

Introduction

  • Language of the machine

    • Instructions(指令)
    • Instruction set(指令集)
  • Computer Designer goals

    • Find a language that makes it easy to build hardware and compiler.(简单易用)
    • Maximize performance(同样的资源性能更好)
    • Minimize cost & energy (同样的性能成本更低)
    • Clarity of its application (易用)
    • Simplicity: reduce design time (便于设计)

Our chosen instruction set: RISC V

各种指令集的区别

Von Neumann’ Computer

如今的计算机是基于两个核心原理构建的:存储程序概念。 这两个原理分别是:

  • 指令被表示为数字;
  • 程序可以像数字一样存储在内存中,以便读取或写入。

四个设计理念:

  1. Simplicity favors regularity 指令集的设计应该尽可能简单,规则。
  2. Smaller is faster 尽可能减少指令集的大小,以便提高速度。
  3. Good design demands good compromises 设计指令集时,需要权衡各种因素。
  4. Make the common case fast 优化常见情况的执行速度。

当设计ISA时,需要**硬件简单--让芯片只实现基本的原语并能快速运行**,指令要规整

Instruction characteristics

指令集的基本结构

operator+operands

Note

不同的操作系统,字的长度不同,比如32位系统,字长为32位(4 Byte),64位系统,字长为64位(8 Byte)。

边界对齐送地址,最后两位是00

RISC-V 指令集

寄存器 ABI 名称 用途描述 saver
x0 zero 硬件 0
x1 ra 返回地址(return address) caller
x2 sp 栈指针(stack pointer) callee
x3 gp 全局指针(global pointer)
x4 tp 线程指针(thread pointer)
x5 t0 临时变量/备用链接寄存器(alternate link reg) caller
x6-7 t1-2 临时变量 caller
x8 s0/fp 需要保存的寄存器/帧指针(frame pointer) callee
x9 s1 需要保存的寄存器 callee
x10-11 a0-1 函数参数/返回值 caller
x12-17 a2-7 函数参数 caller
x18-27 s2-11 需要保存的寄存器 callee
x28-31 t3-6 临时变量 caller

RISC-V 指令集的类型

R-type指令是指令集中的一种类型,它们的操作码字段是固定的,而剩余的字段则根据指令的具体功能而变化。R-type指令通常用于执行算术运算和逻辑运算等操作;R-type指令的格式如下所示:

31 25 24 20 19 15 14 12 11 7 6 0
funct7 rs2 rs1 funct3 rd opcode

rd = rs1 op rs2,有时候rs1,rs2,又称为rs,rt

R-type指令
Instruction Name Meaning
ADD Addition Adds two values and stores the result in the destination register.
SUB Subtraction Subtracts the second value from the first and stores the result in the destination register.
SLT Set Less Than Sets the destination register to 1 if the first value is less than the second (signed), otherwise sets to 0.
SLTU Set Less Than Unsigned Sets the destination register to 1 if the first value is less than the second (unsigned), otherwise sets to 0.
AND Logical AND Performs a bitwise AND operation between two values and stores the result in the destination register.
OR Logical OR Performs a bitwise OR operation between two values and stores the result in the destination register.
XOR Logical XOR Performs a bitwise XOR (exclusive OR) operation between two values and stores the result.
SLL Shift Left Logical Shifts the bits of the first value to the left by the number of positions specified by the second value, filling with zeros.
SRL Shift Right Logical Shifts the bits of the first value to the right by the number of positions specified, filling with zeros.
SRA Shift Right Arithmetic Shifts the bits of the first value to the right by the number of positions specified, maintaining the sign bit.

常见的R-type指令

31 25 24 20 19 15 14 12 11 7 6 0
0000000 rs2 rs1 000 rd 0110011

  • 使用格式 ADD rd,rs1,rs2 rd = rs1 + rs2
  • 溢出将会被忽略

31 25 24 20 19 15 14 12 11 7 6 0
0100000 rs2 rs1 000 rd 0110011

  • 使用格式 SUB rd,rs1,rs2 rd = rs1 - rs2
  • 溢出将会被忽略

31 25 24 20 19 15 14 12 11 7 6 0
0000000 rs2 rs1 010 rd 0110011

  • 使用格式 SLT rd,rs1,rs2 rd = ($signed(rs1) < $signed(rs2)) ? 1 : 0
  • 有符号数的比较

31 25 24 20 19 15 14 12 11 7 6 0
0000000 rs2 rs1 011 rd 0110011

  • 使用格式 SLTU rd,rs1,rs2 rd = (rs1 < rs2) ? 1 : 0
  • 进行无符号数的比较

31 25 24 20 19 15 14 12 11 7 6 0
0000000 rs2 rs1 111 rd 0110011

  • 使用格式 AND rd,rs1,rs2 rd = rs1 & rs2
  • 按位的与操作

31 25 24 20 19 15 14 12 11 7 6 0
0000000 rs2 rs1 110 rd 0110011

  • 使用格式 OR rd,rs1,rs2 rd = rs1 | rs2
  • 执行按位或操作

31 25 24 20 19 15 14 12 11 7 6 0
0000000 rs2 rs1 100 rd 0110011

  • 使用格式 XOR rd,rs1,rs2 rd = rs1 ^ rs2
  • 执行按位异或操作

31 25 24 20 19 15 14 12 11 7 6 0
0000000 rs2 rs1 001 rd 0110011

  • 使用格式 SLL rd,rs1,rs2 rd = rs1 << rs2[4:0]
  • 逻辑左移
  • rs2的低五位进行运算

31 25 24 20 19 15 14 12 11 7 6 0
0000000 rs2 rs1 101 rd 0110011

  • 指令格式: srl rd,rs1,rs2,rd=rs1>>rs2[4:0]
  • rs2 的低5位

31 25 24 20 19 15 14 12 11 7 6 0
0100000 rs2 rs1 101 rd 0110011

  • 指令格式sra rd,rs1,rs2;rd = $signed(rs1) >>> rs2[4:0]
  • 算数右移,高位补符号位(为什么没有算数左移,因为没意义)

使用寄存器和立即数进行数字逻辑运算,以及 load 类指令等的指令格式如下:

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 funct3 rd opcode

立即数为

 imm={{20{inst[31]}}, inst[31:20]}
即将立即数的最高位符号位进行扩展到32位

常见的I-type指令

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 000 rd 0010011

  • 指令格式:addi rd, rs1, imm rd = rs1 + imm
  • imm 范围为12位有符号数字-2048~2047

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 010 rd 0010011

  • 使用格式 slti rd,rs1,imm rd = ($signed(rs1) < $signed(imm)) ? 1 : 0
  • 有符号数的比较

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 011 rd 0010011

  • 使用格式 sltiu rd,rs1,imm rd = (rs1 < imm) ? 1 : 0
  • 进行无符号数的比较,rs1imm都是无符号数

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 111 rd 0010011

  • 使用格式 andi rd,rs1,imm rd = rs1 & imm
  • imm范围在-2048~2047,位数不够时会扩展符号位

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 110 rd 0010011

  • 使用格式 ori rd,rs1,imm rd = rs1 | imm
  • imm范围在-2048~2047,位数不够时会扩展符号位

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 100 rd 0010011

  • 使用格式 xori rd,rs1,imm rd = rs1 ^ imm
  • imm范围在-2048~2047,位数不够时会扩展符号位
  • 需要注意的是xori rd,rs1,-1等价于与全1异或:rd=~rs1

31 25 24 20 19 15 14 12 11 7 6 0
0000000 shamt rs1 001 rd 0010011

  • 使用格式 slli rd,rs1,shamt rd = rs1 << shamt
  • 逻辑左移
  • shmat在原来rs2的位置上,为五位立即数;此时空出来相当于原来的func7

31 25 24 20 19 15 14 12 11 7 6 0
0000000 shamt rs1 101 rd 0010011

  • 使用格式 srli rd,rs1,shamt rd = rs1 >> shamt
  • 逻辑右移
  • shmat在原来rs2的位置上,为五位立即数;此时空出来相当于原来的func7

31 25 24 20 19 15 14 12 11 7 6 0
0100000 shamt rs1 101 rd 0010011

  • 使用格式 srai rd,rs1,shamt rd = $signed(rs1) >>> shamt
  • 算数右移,高位补符号位

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 000 rd 1100111

  • 使用格式 jalr rd,rs1,imm rd = pc+4; pc = (rs1 + imm) & ~1,即最低位为0
  • 可以实现任意位置的跳转

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 000 rd 0000011

  • 使用格式 lb rd,imm(rs1) rd = {{24M[rs1+imm][7]},M[rs1 + imm][7:0]}
  • 从内存的rs1+imm地址处读取一个字节的数据,符号扩展到32位,存到rd

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 001 rd 0000011

  • 使用格式 lh rd,imm(rs1) rd = {{16M[rs1+imm][15]},M[rs1 + imm][15:0]}

  • 从内存的rs1+imm地址处读取一个半字的数据,存到rd的低16位,符号扩展到32位

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 010 rd 0000011

  • 使用格式 lw rd,imm(rs1) rd = M[rs1 + imm]
  • 从内存的rs1+imm地址处读取一个字的数据,存到rd

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 100 rd 0000011

  • 使用格式 lbu rd,imm(rs1) `rd = M[rs1 + imm][7:0]
  • 从内存的rs1+imm地址处读取一个字节的数据,零扩展到32位,存到rd中(高位全0)

31 20 19 15 14 12 11 7 6 0
imm[11:0] rs1 101 rd 0000011

  • 使用格式 lhu rd,imm(rs1) rd = M[rs1 + imm][15:0]
  • 从内存的rs1+imm地址处读取一个半字的数据,零扩展到32位,存到rd中(高位全0)

31 20 19 15 14 12 11 7 6 0
000000000000 00000 000 00000 1110011
- 使用格式 ecall 系统调用

31 20 19 15 14 12 11 7 6 0
000000000001 00000 000 00000 1110011
- 使用格式ebreak ,将控制流转到调试环境

store 类指令,将寄存器中的数据存储到内存中,存储的大小由func3决定,没有rd寄存器

31 25 24 20 19 15 14 12 11 7 6 0
imm[11:5] rs2 rs1 funct3 imm[4:0] opcode
立即数为
imm = {{20{inst[31]}}, inst[31:25], inst[11:7]}
rd的5位和func7的7位一共12位组合成一个立即数

常用的S-type指令

31 25 24 20 19 15 14 12 11 7 6 0
imm[11:5] rs2 rs1 000 imm[4:0] 0100011

  • 使用格式 sb rs2,imm(rs1) M[rs1 + imm] = rs2[7:0]
  • rs2的低8位存到内存的rs1+imm地址处

31 25 24 20 19 15 14 12 11 7 6 0
imm[11:5] rs2 rs1 001 imm[4:0] 0100011
- 使用格式 sh rs2,imm(rs1) M[rs1 + imm] = rs2[15:0] - 将rs2的低16位存到内存的rs1+imm地址处

31 25 24 20 19 15 14 12 11 7 6 0
imm[11:5] rs2 rs1 010 imm[4:0] 0100011

  • 使用格式 sw rs2,imm(rs1) M[rs1 + imm] = rs2
  • rs2存到内存的rs1+imm地址处

在RISC-V指令集中,B型(B-type)指令用于条件分支,根据比较结果决定是否跳转到指定的偏移地址。B型指令通常包含两个寄存器进行比较以及一个立即数偏移量(表示跳转的距离)。

31 25 24 20 19 15 14 12 11 7 6 0
imm[12,10:5] rs2 rs1 funct3 imm[4:1,11] opcode

立即数为

imm={{19{inst[31]}}, inst[31], inst[7], inst[30:25], inst[11:8], 1'b0}
最低位为0,不存;扩展到imm[12]位;将13位拼接完后,剩下高19位用inst[31]符号位填充,此时imm[11]可以不是符号位;imm[12]是符号位

常用的B-type指令

31 25 24 20 19 15 14 12 11 7 6 0
imm[12,10:5] rs2 rs1 000 imm[4:1,11] 1100011

  • 使用格式:beq rs1,rs2,imm if(rs1 == rs2) pc = pc + imm
  • 可以跳转到\(\pm 2^{12}Byte\)的位置,即\(\pm 4KiB\)

31 25 24 20 19 15 14 12 11 7 6 0
imm[12,10:5] rs2 rs1 001 imm[4:1,11] 1100011

  • 使用格式:bne rs1,rs2,imm if(rs1 != rs2) pc = pc + imm
  • 可以跳转到\(\pm 2^{12}Byte\)的位置,即\(\pm 4KiB\)

31 25 24 20 19 15 14 12 11 7 6 0
imm[12,10:5] rs2 rs1 100 imm[4:1,11] 1100011

  • 使用格式:blt rs1,rs2,imm if($signed(rs1) < $signed(rs2)) pc = pc + imm
  • 有符号数

31 25 24 20 19 15 14 12 11 7 6 0
imm[12,10:5] rs2 rs1 101 imm[4:1,11] 1100011

  • 使用格式:bge rs1,rs2,imm if($signed(rs1) >= $signed(rs2)) pc = pc + imm
  • 有符号数

31 25 24 20 19 15 14 12 11 7 6 0
imm[12,10:5] rs2 rs1 110 imm[4:1,11] 1100011

  • 使用格式:bltu rs1,rs2,imm if(rs1 < rs2) pc = pc + imm
  • 无符号数比较

31 25 24 20 19 15 14 12 11 7 6 0
imm[12,10:5] rs2 rs1 111 imm[4:1,11] 1100011

  • 使用格式:bgeu rs1,rs2,imm if(rs1 >= rs2) pc = pc + imm
  • 无符号数比较

31 12 11 7 6 0
imm[31:12] rd opcode

没有源操作数,只有目的操作数,立即数为

imm={inst[31:12], 12'b0}

U-type指令

31 12 11 7 6 0
imm[31:12] rd 0110111

  • 使用格式 lui rd,imm rd = imm << 12
  • imm位存入rd高20位
  • imm不能超过20位

31 12 11 7 6 0
imm[31:12] rd 0010111

  • 使用格式 auipc rd,imm rd = pc + imm << 12
  • aupic意思是add upper immediate to pc,将imm 加载到高 20 位,然后加上 pc 值
  • imm不能超过20位

31 12 11 7 6 0
imm[20,10:1,11,19:12] rd opcode

立即数为

imm={{11{inst[31]}}, inst[31], inst[19:12], inst[20], inst[30:21], 1'b0}
imm最低位0不存,此时imm[20]是符号位,imm相当于21位有符号数 ,跳转范围是\(\pm 2^{20}\)

JAL指令

31 12 11 7 6 0
imm[20,10:1,11,19:12] rd 1101111

  • 使用格式 jal rd,imm rd = pc + 4; pc = pc + imm
  • pc+4存入rd,然后跳转到pc+imm
  • Jal指令的跳转范围是\(\pm 2^{20}Byte\),即\(\pm 1MiB\)