计算机组成原理 笔记 1
计算机组成原理 指令与数据
计算机指令系统
指令是计算机运行的最小的功能单元,计算机的指令系统是该计算机提供的全部指令
指令的功能与分类
- 算数与逻辑运算指令
- 加、减、乘、除等
- 与、或、非、异或等
- 移位操作指令
- 算数右移(补符号位)、逻辑右移、逻辑左移、循环左移
- 数据传送指令
- 寄存器之间
- 寄存器与内存间
- 不同内存之间
- 输入输出
- 计算器与外设之间
- 跳转指令
- 无条件与条件
- 调用与返回指令
- 堆栈操作指令
- 其它
指令表示
指令 = 操作码 + 操作数或操作数地址(寄存器、内存或外设)
即对哪些数据做什么操作
操作码可以是定长或变长,定长操作码的译码速度更快,变长操作码可以表示的指令更多
指令是定长的,和机器有关
操作码的扩展
显然,操作码的个数会限制指令系统的长度,因此可以对操作码进行扩展,从而支持更多样化的指令
扩展的方式为:充分利用空闲的位置,例如32位机器上,如果有2个8位地址段作为操作数,则有至多16位可以用于表示操作码,而如果只有1个8为地址段作为操作数,则有至多24位可以用于表示操作码
寻址方式
由于操作数可能需要在某一个地址中进行读取,因此需要指定指令系统的寻址方式:
- 立即数寻址:操作数直接给出,无需寻址
- 直接寻址:给出内存中的地址
- 寄存器寻址:给出操作数所存放在的寄存器编号,则
addr = (base)
- 变址寻址:给出寄存器编号和立即数,则
addr = (base) + offset
- 相对寻址:给出地址相对程序计数器PC的偏移
- 间接寻址:通过上述的某种方式,给出指向操作数的指针的地址
- 基址寻址:在计算机中设置一个寄存器用于存放固定的基址,指令中给出偏移量
- 堆栈寻址:利用
sp
进行寻址(变址寻址的一种)
Riscv 指令
Riscv为定长操作码,如下图,从上到下依次为:寄存器型、立即数型、存储型、分支指令、跳转指令、大立即数

由于指令长度为32位,因此U型指令是操作一些长立即数,例如向x1中写入0x12345678等
寄存器

算数、位运算、移位指令
用后缀指明操作数的类型,无u
代表有符号数,有u
代表无符号数,i
代表第二个操作数是立即数
op dst, src1, src2
: R型opi dst, src, imm
: I型opu dst, src1, src2
: R型
操作有:
add sub mul div rem neg
and or xor not
sll srl sra
lui reg, imm
: U型,加载立即数到指定寄存器的高20位
其中,mul
的结果是64位,但是dst
指向的是32位,因此乘法指令有如下变体:
mul rdl, rs1, rs2 <==> rdl = (rs1 * rs2)[31:0]
mulh rdh, rs1, rs2 <==> rdh = (rs1 * rs2)[63:32]
mulhu rdh, rs1, rs2 <==> rdh = (unsigned(rs1) * (unsigned)rs2)[63:32]
mulhsu rdh, rs1, rs2 <==> rdh = (rs1 * (unsigned)rs2)[63:32]
访存指令
Riscv中有专属的Load/Store
指令用于操作内存,其他指令只能操作寄存器,采用变址寻址的方式
l/s reg, offset(base)
: Load为I型,Store为S型
允许以字节为基本单位进行读写:
- 一字节:
lb, sb
- 双字节:
lh, sh
- 四字节:
lw, sw
注:
- Riscv是小端
lb lh
会做符号扩展,而lbu lhu
会做0
扩展
分支与跳转
比较指令有:
slt rd, rs1, rs2: rd = 1 if rs1 < rs2 else 0
: R型sgt rd, rs1, rs2: rd = 1 if rs1 > rs2 else 0
: R型
同理还有snez, seqz
与0进行比较
分支跳转指令有:
beq rs1, rs2, label: goto label if rs1 == rs2
: B型bne rs1, rs2, label: goto label if rs1 != rs2
: B型
同理也有blt bgt
等
无条件跳转指令有
jal rd, label: goto label and rd = pc + 4
: J型jalr rd, base, offset: goto [(base) + offset] and rd = pc + 4
: J型
伪指令
一些更加直观的指令,会被翻译成上述指令
mv dst, src = addi dst, src, 0
li dst, imm
la dst, label
ret = jalr x0, x1, 0
函数调用
参数:x10 - x17(a0 - a7)
为前8个参数,后面的参数倒序入栈,x1(ra)
为返回值
注意需要维护好栈帧指针,并且调用者和被调用者需要维护好对应寄存器
数据表示与纠错
逻辑数据
- True: 1
- False: 0
字符数据
ASCII编码
占用1字节,表示128个西文字符

UNICODE字符集
为每种语言的每个字符设定了统一且唯一的二进制编码,兼容ASCII
UTF-8编码

- 变长字符编码,长度由首字节确定
- 字符除首字节外均以
10
开头
字符显示
- 点阵字体:将字符展示在GUI界面中的方式,点阵字体是其中最简单的一种,即利用黑白位图来表示
- 矢量字体:用多条曲线来表示字符,每条曲线存储一部分关键点,显示的时候平滑连接关键点并填充
数值数据
整数
第一位为符号位,后续为数值位
- 正数的原=补=反
- 0有两个原码与反码(),仅有1个补码
- 负数:反码为数值位取反,补码为反码+1
浮点数
浮点数组成为[s, exp, frac]
,分别为符号位、阶码(表示方式为移码)与尾码(表示方式为原码)
bias = 2^(len(exp) - 1) - 1
exp != 0, exp != 11..11
时为规格化数,此时:E = exp - bias
M = 1.frac
num = (s ? -1 : 1) * M * 2^E
exp == 0
时为非规格化数,此时:E = 1 - bias
M = 0.frac
num = (s ? -1 : 1) * M * 2^E
exp == 11..11, frac == 0
时为inf
- 其他情况为
NaN
浮点数加减:
- 操作阶码,阶码较小的右移,阶码大的为结果的阶码
- 尾数加减
- 规格化处理
- 舍入操作
- 检查阶码是否溢出
浮点数乘除:
- 阶码直接加减
- 尾数乘除法
- 规格化处理
- 舍入操作
- 检查阶码溢出
检错纠错码
码距指任意两个合法编码之间不同的二进制位数目的最小值,当码距为1的时候无检错能力
常见的检错纠错码有:奇偶校验码、海明校验码与循环冗余校验码
奇偶校验码
在k位数据码之外增加1位校验位,使得其中取值为1的位数总保持为奇数或偶数,码距为2
如偶校验:1101 -> 11101
,奇校验1101 -> 01101
电路上来看是取异或即可
海明校验码
并行数据,为k位数据设定r位校验码,使其能够:
- 能够发现并改正k+r中任意一位出错
- 能够发现k+r中任意两位同时出错
码距为4
则k与r之间应该满足的关系是:
- :此时即为用个编码分别表示出错的位数或都不出错
- :用为校验码为出错位编码,单独设置一位用于区分是1位还是2位出错(总校验位)
编码方案:
- 将校验位依次安排在2的幂次位,将数据位依次排布在剩下的位置
- 将数据位的编号拆分成2的幂的和,则所出现的幂对应位置上校验位负责对该数据位进行校验
- 校验位的值即为其所校验的数据的异或
- 总校验位的值为所有数据的异或
译码方案:对收到的数据的数据位再次编码并比较