CS61C学习笔记(四)-RISCV-Formats
引言
现在我们来到了第三层——Machine Language Program
接下来将介绍汇编语言是怎么转化成机器码的
Consequence #1: Everything Has a Memory Address
- 由于所有的指令和数据都存储在内存中,所以一切都有一个内存地址:指令、数据字
- 这意味着分支和跳转都使用这些地址
- C 指针只是内存地址:它们可以指向内存中的任何东西
- 不受约束的地址使用可能导致严重的错误;在 C 语言中避免错误是你的责任;而在 Java 语言设计中,这种使用受限
- 一个寄存器保存着当前正在执行的指令的地址:“程序计数器”(Program Counter,简称 PC)
- 基本上就是一个指向内存的指针
- 英特尔称之为指令指针(Instruction Pointer,简称 IP)
Consequence #2: 二进制的兼容
- 程序以二进制形式分发
- 程序绑定到特定的指令集
- 手机和个人电脑的版本不同
- 新机器希望运行旧程序(“二进制”文件)以及编译到新指令的程序
- 这导致了“向后兼容”的指令集随着时间的推移而演变
- 选择英特尔8088处理器作为1981年首款IBM PC的处理器是当今最新PC仍使用80x86指令集的主要原因;1981年的PC程序今天仍然可以运行
指令作为数字
大多数我们处理的数据都是以字(32位块)为单位:
每个寄存器是一个字
lw
和sw
每次都访问一个字的内存那么我们如何表示指令呢?
- 记住:计算机只能理解1和0,所以汇编器字符串“add x10,x11,x0”对硬件来说是无意义的
- RISC-V追求简洁:既然数据是以字为单位,那么指令也固定为32位的字
- 同样的32位指令用于RV32、RV64、RV128
一字为32位,因此将指令字分为“字段”
每个字段向处理器传达一些关于指令的信息
我们可以为每条指令定义不同的字段,但RISC-V追求简洁,所以定义了六种基本类型的指令格式:
- R格式用于寄存器-寄存器算术运算
- I格式用于寄存器-立即数算术运算和加载
- S格式用于存储
- B格式用于分支(S格式的一个小变种)
- U格式用于20位上位立即数指令
- J格式用于跳转(U格式的一个小变种)
R-Format布局
32-bit instruction word divided into six fields of varying numbers of bits each: 7+5+5+3+5+7 = 32
opcode: 部分指定了是什么指令
- 注意:对于所有R型格式的寄存器-寄存器算术指令,该字段等于
0110011
。
- 注意:对于所有R型格式的寄存器-寄存器算术指令,该字段等于
funct7
和funct3
:结合opcode,这两个字段描述了要执行的操作。rs1
(Source Register #1):指定包含第一个操作数的寄存器。rs2
:指定第二个操作数的寄存器。rd
(Destination Register):指定将接收计算结果的寄存器。每个寄存器字段包含一个5位无符号整数(0-31),对应一个寄存器编号(x0-x31)。
例子
所有 RV32 R-format 指令
图片中的“2’s comp of rs2”意思是“rs2的二进制补码”
在表格中,“2’s comp of rs2”标注在funct7字段中的
0100000
这一行,表示:
对应指令是
sub
(减法)。这个funct7字段的具体含义是告诉处理器,这条指令要对寄存器
rs2
中的值取二进制补码,然后与rs1
中的值相加,从而实现减法操作。具体解释
add
指令的funct7字段是0000000
,表示正常加法操作:rd = rs1 + rs2
。
sub
指令的funct7字段是0100000
,表示减法操作:rd = rs1 - rs2
。在计算机内部,减法操作可以通过加上一个数的二进制补码来实现。因此,这里“2’s comp of rs2”表示对rs2
取二进制补码然后再相加。对于
sra
和srl
来说,funct7字段中的第一个1
(即0100000
中的第2位)在这里作为一个标识符,用于区分这两种不同的右移操作。
I-Format 布局
Register-Immediate Arithmetic Instructions
例子
所有RV32 I-Format 算术指令
Load 指令
例子
所有Load Instructions
S-Format 布局
为什么要分离immediate
字段
- store操作后没有寄存器可以存入
- 其两个源寄存器
- 一个是存数据的
- 一个是存地址的,加上偏移量后把数据移动进去
- 其两个源寄存器
同时,也是因为为了和其他指令有相同的寄存器字段位置,方便硬件操作
例子
所有Store指令
前三总结
Program Counter(PC) 的更新
PC
对多数指令来说,PC = PC + 4
Branch更新PC到Jump
PC相对寻址法
B-Format布局
偏移的缩放
对于条件分支的 12-bit 的 immediate
字段来说:
单位是 2 bytes(16-bit “half-words“)
布局
为什么要把11移到最低位???
- 对于最高的7位
- 最高位为符号位
- B-type这样子做可以和I-type和S-type保持对齐
- 对于最低的那几位
- 因为对于B-type我们总是乘2,所以最低位的0我们不存,因此空了一位出来,因此把11移到最低位来保持对齐
例子
16 / 2 = 8,因此是0x100,编码进Imm的时候因为imm的单位是2,所以左移一位,即0x1000,抵消了除的效果
所有B-Format指令
J-Format指令
jal指令和j伪代码
J-Format布局
U-Format布局
lui
and addi
实现了Long Immediates
lui
的极端情况:addi
符号扩展
addi
可能会符号位扩展,导致和实际不符
解决方法:lui
先加上一再addi