Introduction

计算机程序及分类

高级语言

汇编语言

机器语言

Von-Newmann 计算机

指令和指令系统

指令系统地位

指令功能分类

指令格式

指令格式:操作码,操作数地址的二进制分配方案

  • 操作码:指令的操作功能
  • 操作数地址:操作数存放的地址,或者操作数本身

指令字:完整的一条指令的二进制表示 指令字长:指令字中二进制代码的位数

  • 机器字长:计算机能够直接处理的二进制数据的位数
  • 指令字长(字节倍数):0.5,1,2,……个机器字长
  • 定长指令字结构 变长指令字结构
  • 定长操作码 扩展操作码

寻址方式

寻址方式(又称编址方式)指的是确定本条指令的操作数地址及下一条要执行的指令地址的方法。

  • 不同的计算机系统,使用数目和功能不同的寻址方式,其实现的复杂程度和运行性能各不相同。
  • 有的计算机寻址方式较少,而有些计算机采用多种寻址方式。
  • 通常需要在指令中为每一个操作数专设一个地址字段,用来表示数据的来源或去向的地址。
    • 在指令中给出的操作数(或指令)的地址被称为形式地址,
    • 使用形式地址信息并按一定规则计算出来或读操作得到的一个数值才是数据(或指令)的实际地址。
  • 在指令的操作数地址字段,可能要指出:
    1. 运算器中的累加器的编号或专用寄存器名称(编号)
    2. 输入/输出指令中用到的 I/O 设备的入出端口地址
    3. 内存储器的一个存储单元(或一 I/O 设备)的地址

评价计算机性能的指标

  • 吞吐率
  • 响应时间
  • 衡量性能的指标
    • MIPS
    • CPI
    • CPU Time
    • CPU Clock
  • Benchmark software

指令系统分类

  • CISC
  • RISC
  • VLIW:超长指令字(VLIW:Very Long Instruction Word)
    • 将简短而长度统一的精简指令组合出超长指令,每次运行一条超长指令,等于并发运行多条短指令。
    • 例子:Intel 安腾指令集

RISC-V 简介

RV32 指令格式

六种基本指令格式,分别是:

  • 用于寄存器-寄存器操作的 R 类型指令,
  • 用于短立即数和访存 load 操作的 I 型指令,
  • 用于访存 store 操作的 S 型指令,
  • 用于条件跳转操作的 B 类型指令,
  • 用于长立即数的 U 型指令
  • 用于无条件跳转的 J 型指令。

RV32 指令集的优势:

  1. 所有的指令都是 32 位字长,有 6 种指令格式,简化了指令解码;
  2. RISC-V 指令提供三个寄存器操作数,而不是像 x86-32 一样,让源操作数和目的操作数共享一个字段——当一个操作天然就需要有三个不同的操作数,但是 ISA 只提供了两个操作数时,编译器或者汇编程序程序员就需要多使用一条 move(搬运)指令,来保存目的寄存器的值。
  3. 在 RISC-V 中对于所有指令,要读写的寄存器的标识符总是在同一位置,意味着在解码指令之前,就可以先开始访问寄存器。在许多其他的 ISA 中,某些指令字段在部分指令中被重用作为源目的地,在其他指令中又被作为目的操作数(例如,ARM-32 和 MIPS-32)。因此,为了取出正确的指令字段,我们需要时序本就可能紧张的解码路径上添加额外的解码逻辑,使得解码路径的时序更为紧张。
  4. 这些格式的立即数字段总是符号扩展,符号位总是在指令中最高位。这意味着可能成为关键路径的立即数符号扩展,可以在指令解码之前进行。

[! note] 全 0 和全 1 指令都是非法。 为了帮助程序员,所有位全部是 0 是非法的 RV32I 指令。因此, 试图跳转到被清零的内存区域的错误跳转将会立即触发异常,这可以帮助调试。

类似地,所有位全部是 1 的指 令也是非法指令,它将捕获其他常见的错误,诸如未编程的非易失性内存设备、断开连接的内存总线或者坏掉的内存芯片。

为了给 ISA 扩展留出足够的空间,最基础的 RV32I 指令集只使用了 32 位指令字中的编码空间的不到八分之一。架构师们也仔细挑选了 RV32I 操作码,使拥有共同数据通路的 指令的操作码位有尽可能多的位的值是一样的,这简化了控制逻辑。最后,当我们看到,B 和 J 格式的分支和跳转地址必须向左移动 1 位以将地址乘以 2,从而给予分支和跳转指令更大的跳转范围。RISC-V 将立即数中的位从自然排布进行了一些移位轮换,将指令信号的扇出和立即数多路复用的成本降低了近两倍,这也简化了低端实现中的数据通路逻辑。

RV32I

特权指令

RV32F

RV32D

扩展指令

RV32 汇编举例

int sum() { 
	int sum = 0; 
	for (int i = 1; i < 11; i++) sum += i; 
	return sum 
}
#-Og版本

sum:
	li a5,1       # load imm to register a5, a5等价于i
	li a0,0       # a0是返回值寄存器
.L2:
	li a4,10      # 循环10次,a4存储终止条件
	bgt a5,a4,.L4 # if a5>a4, jump to .L4
	add a0,a0,a5  # a0+a5 -> a0
	addi a5,a5,1  # a5+1 -> a5
	j .L2         # jump to .L2, loop
.L4:
	ret           # ret, 并返回a0中的值

# -O2版本
sum:
	li a0,55 
	ret
int fibo[10]; 
void fib() { 
	int i; 
	fibo[0]=1; 
	fibo[1] =1; 
	for ( i=2 ; i<10; i++) fibo[i]= fibo[i-1] + fibo[i-2]; }
	.align 2                  # 对齐
	.globl fib                # 声明fib为全局符号
	.type fib, @function      # 指定fib符号是一个函数
fib: 
	lui a5,%hi(fibo)          # 获取fibo的高位地址并加载到a5中 
	addi a4,a5,%lo(fibo)      #  
	li a3,1                   # a3 = 1 
	addi a5,a5,%lo(fibo)      # set a5 = address of fibo 
	sw a3,0(a4)               # fibo[0] = 1,a3转存到a4所存地址+0偏移处
	sw a3,4(a4)               # fibo[1] = 1 
	addi a2,a5,32             # a2 = address of fibo[8] 
	li a4,1                   # a4 = 1 
	j .L3                     # goto L3 
.L5: 
	lw a4,4(a5)               # a4 = a5[1] 
	lw a3,0(a5)               # a3 = a5[0] 
.L3: 
	add a4,a4,a3              # a4 = a4 + a3 
	sw a4,8(a5)               # a5[2] = a4 
	addi a5,a5,4              # a5 += 4 (points to the next entry) 
	bne a5,a2,.L5             # not finished? goto L5 
	ret