计算机组成原理 笔记 1

计算机组成原理 指令与数据

计算机指令系统

指令是计算机运行的最小的功能单元,计算机的指令系统是该计算机提供的全部指令

指令的功能与分类

  • 算数与逻辑运算指令
    • 加、减、乘、除等
    • 与、或、非、异或等
  • 移位操作指令
    • 算数右移(补符号位)、逻辑右移、逻辑左移、循环左移
  • 数据传送指令
    • 寄存器之间
    • 寄存器与内存间
    • 不同内存之间
  • 输入输出
    • 计算器与外设之间
  • 跳转指令
    • 无条件与条件
  • 调用与返回指令
  • 堆栈操作指令
  • 其它

指令表示

指令 = 操作码 + 操作数或操作数地址(寄存器、内存或外设)

即对哪些数据做什么操作

操作码可以是定长或变长,定长操作码的译码速度更快,变长操作码可以表示的指令更多
指令是定长的,和机器有关

操作码的扩展

显然,操作码的个数会限制指令系统的长度,因此可以对操作码进行扩展,从而支持更多样化的指令

扩展的方式为:充分利用空闲的位置,例如32位机器上,如果有2个8位地址段作为操作数,则有至多16位可以用于表示操作码,而如果只有1个8为地址段作为操作数,则有至多24位可以用于表示操作码

寻址方式

由于操作数可能需要在某一个地址中进行读取,因此需要指定指令系统的寻址方式:

  • 立即数寻址:操作数直接给出,无需寻址
  • 直接寻址:给出内存中的地址
  • 寄存器寻址:给出操作数所存放在的寄存器编号,则addr = (base)
  • 变址寻址:给出寄存器编号和立即数,则addr = (base) + offset
  • 相对寻址:给出地址相对程序计数器PC的偏移
  • 间接寻址:通过上述的某种方式,给出指向操作数的指针的地址
  • 基址寻址:在计算机中设置一个寄存器用于存放固定的基址,指令中给出偏移量
  • 堆栈寻址:利用sp进行寻址(变址寻址的一种)

Riscv 指令

Riscv为定长操作码,如下图,从上到下依次为:寄存器型、立即数型、存储型、分支指令、跳转指令、大立即数

RISCV指令格式
RISCV指令格式

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

寄存器

RISCV中的寄存器
RISCV中的寄存器

算数、位运算、移位指令

用后缀指明操作数的类型,无u代表有符号数,有u代表无符号数,i代表第二个操作数是立即数没有`subi`

  • 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

注:

  1. Riscv是小端
  2. 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个西文字符

ASCII字符集
ASCII字符集

UNICODE字符集

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

UTF-8编码

UTF-8编码
UTF-8编码
  • 变长字符编码,长度由首字节确定
  • 字符除首字节外均以10开头

字符显示

  • 点阵字体:将字符展示在GUI界面中的方式,点阵字体是其中最简单的一种,即利用黑白位图来表示
  • 矢量字体:用多条曲线来表示字符,每条曲线存储一部分关键点,显示的时候平滑连接关键点并填充

数值数据

整数

第一位为符号位,后续为数值位

  • 正数的原=补=反
  • 0有两个原码与反码(±0\pm 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之间应该满足的关系是:

  • 2rk+r+12^{r} \geq k + r + 1:此时即为用2r2^{r}个编码分别表示出错的位数或都不出错
  • 2r1k+r2^{r - 1} \geq k + r:用r1r - 1为校验码为出错位编码,单独设置一位用于区分是1位还是2位出错(总校验位)

编码方案:

  1. 将校验位依次安排在2的幂次位,将数据位依次排布在剩下的位置
  2. 将数据位的编号拆分成2的幂的和,则所出现的幂对应位置上校验位负责对该数据位进行校验
  3. 校验位的值即为其所校验的数据的异或
  4. 总校验位的值为所有数据的异或

译码方案:对收到的数据的数据位再次编码并比较