CSAPP(深入理解计算机系统)

前言

自己这段时间上了微机原理,想起来这本书也看完了,就一同综合做个笔记。因而有部分是只属于MIPS的,我会标注出来,如果不需要应付考试的话我是不推荐读里面相关段落的一个字的,而为应付考试的话标注属于MIPS的应为重点,利用crtl +F 搜索MIPS即可

第二章:信息的表示与处理

总纲

主要是二进制的比特串的存放规则与译码规则的不同

2.1信息储存

2.1.1 字节

储存的基本单元:

  • 大多数计算机利用8位的块(字节byte)来作为最小的可寻址的储存器单位

即如地址0x00000001 中储存了0xcc 这样的数据

2.1.2 字

字:

  • 每台计算机拥有字长(word size)指明整数与指针数据的表称大小,也就是CPU一次能处理的位数
  • 同时也是虚拟地址的寻址空间

2.1.4 寻址与字节顺序

寻址:

  • 多字节对象被存储为连续的字节序列,对象的地址为所使用的字节中最小的地址

如int x地址为0x100; 即&x = 0x100,x的四个字节储存在0x100 0x101 0x102 0x103

  • 字节顺序(大端机与小端机):

大端机:最高有效字节在最前面
小端机:最高有效字节在最后面
如 0x01234567 高位是0x01 低位是0x67

地址 0x100 0x101 0x102 0x013
大端机 0x01 0x23 0x45 0x67
小端机 0x67 0x45 0x23 0x01

- show_bytes程序

  //可用于按位模式显示数据
  #include
  typedef unsigned char *byte_pointer;

  template <typename T>
  void show_bytes(T x)
  {
    byte_pointer start = (byte_pointer)&x;
    for (int i =0;i<sizeof(T);++i)
    {
        printf("%.2x", start[i]);
    }
    printf("\n");
  }

2.1.10位移运算

  • 左移k位:丢弃最高的k位,右端补零
  • 右移k位:逻辑右移:左端补0

    ​算术右移:左端补1 (有符号数几乎都是用算术右移)

  • Attention: 加减优先级比位移高

2.2 整数表示

注意,以下仅讨论整数,那么提升,截取等都只对整数而言.

2.2.2 无符号数编码

B2Uw(BinaryToUnsigned)B2Uw(x⃗ )=.i=0w1xi2i

2.2.3 补码编码

B2T_w(Binary to Two’s-complement)

B2Tw(x⃗ )=.xw12w1+i=0w2xi2i

反码与原码

  • 反码(Ones’ Complement): 为 补码 的最高有效位的权 小一

    B2Ow(x⃗ )=.xw1(2w11)+i=0w2xi2i

  • 原码(Sign-Magnitude):最高有效位是符号位,用于确定剩下的位应该取正还是负

B2Sw(x⃗ )=.(1)xw1.i=0w2xi2i

  • 原码,反码,补码关系

    • 正数: 三者相同
    • 负数:
    • 反码: 原码符号位以外的各位求反
    • 补码: 原码除符号位外取反(反码)后在末尾加1

2.2.4 有符号数与无符号数之间的转换

强制类型转换: 结果保持位值不变,只是改变了解释这些位的方式

Attention: 隐式/显示 类型转换 见Cpp_Prime 4.11 Type Conversions 笔记

2.2.6 扩展一个数字的位表示

  • 零扩展(zero extension):将无符号数变大,在开头添0
  • 符号扩展(sign extension):补码数字变大,添加 最高有效位值 的副本

2.2.7 截断数字

简单的丢弃掉前面多的位数.

2.3 整数运算

  • 就是进行位级别的运算,只是注意溢出,这里给出一个例子
#include 
using namespace std;
float sum_elements(float a[], unsigned length)
{
    float sum = 0;
    for (int i=0;i<= length-1;++i)//由于length 为unsigned,当length=0时,length-1会下溢
    {
        sum += a[i];
    }
    return sum;
}
int main()
{
    float x[4] = { 1.0,2.0,3.0,4.0 };
    cout << sum_elements(x, 0) << endl;
}
  • 关于乘以常数,可以利用位运算加速,如 x14=x(2421)=(x<<4)(x<<1)

2.4 浮点数

2.4.2 IEEE浮点数表示

这里先给出数学表达式,再讲述其中符号的意思,再说明如何自己译码并进行计算.

  1. 数学表达

V=(1)s×M×2E

  1. 符号解释

    • 符号(sign) s

    • 尾数(significand) M

    • 阶码(exponent) E

    将浮点数的位表示划分为三个字段,分别为这些值进行译码

    • 一个单独的符号位s直接编码符号s
    • k位的阶码字段, exp=ek1...e1e0 编码阶码E
    • n位小数字段 frac=fn1...f1f0 编码尾数M,但其也依赖于阶码字段的值

单精度float 32位 各个字段

31 30 23 22 0
s exp frac

​ 双精度double 64位 各个字段

63 62 52 51 0
s exp frac

3. 译码

以float说明如何解释各个字段并读出十进制值这里记住偏置 Baias=2k11

  1. 格式化的值(即阶码为不为全0 或者全1)那么阶码为将阶码段值以无符号解释出来(设为e)后减去偏置 即 E=eBias 小数字段frac为描述小数值 f=0.fn1...f1f0 此时的尾数 M=1+f 即自带了一个整数1
  2. 非格式化的值(阶码为全0) 此时 E=1Bias M=f , 注意此时不包含隐含的1
  3. 无穷大(阶码全为1 并且 小数段全为0)
  4. NaN(阶码全为1 但是 小数字段不为全0) 不是数

2.4.5 浮点运算(与补充)

由于以下运算步骤,因而1+1e120-1e120 = 0,而1e120-1e120+1 = 1

加减计算方式

大体分为六步

  1. 0操作数检查
  2. 比较阶码,并完成对阶码
  3. 尾数求和运算
  4. 结果规格化
  5. 舍入处理
  6. 溢出处理

这里用一个例子综合地回顾浮点数的表示与运算(also MIPS)

1.3+3.7

  1. 1.3(float表示):易知s = 0

    1.3二进制数为1.3_d = 1.0 1001 1001 1001 10011001 1001..._b那么为规范数.

    其阶码为0,加上偏置(bias = 127) 得到阶码位为127_d = 0111 1111_b

    然后其小数位就需要去除整数部分的1,然后进行舍入到23位,为0 1001 1001 1001 1001 1001 10

    最后其二进制表示就是0(符号位)0111 1111(阶码位)0 1001 1001 1001 1001 1001 10

    整理为16进制就是0x3fa66666 在小端机上就会显示为0x66 66 a6 3f

  2. 3.7(float表示):易知 s= 0

    3.7二进制数为3.7_d = 11.1 0110 0110 0110 0110 0110 0110 0110..._b那么为规范数

    小数点需左移一位,那么阶码为1,加上偏置得到阶码位128_d = 1000 0000_b

    左移后数为1.11 0110 0110 0110 0110 0110 0110 0110..._b

    然后进行小数位舍入得到11 0110 0110 0110 0110 0110 1注意左后的1是舍入得到的

    最后其二进制表示就是0(符号位)1000 0000(阶码位)11 0110 0110 0110 0110 0110 1

    整理为16进制就是0x406ccccd 在小端机上就会显示为0xcd cc 6c 40

  3. 1.3 + 3.7 相加

    1. 均不为0

    2. 1.3阶码小,进行对阶,将小数部左移1位,相当于

      210.101001100110011001100110...

    3. 此时再将位数相加,这里要注意3.7尾数前有隐含的1,而1.3对阶后没有了隐含的1,那么相当于

      1.1101 1001 1001 1001 1001 101 + 0.1010 0110 0110 0110 0110 011

      的到10.1000 0000 0000 0000 0000 000

    4. 规范化,由上一步算出来的式子还需要左移一位得到规范的尾数,那么阶码+1 得到为2 加上偏置为129.

      阶码 129_d =1000 0001尾数变为010 0000 0000 0000 0000 0000

      得到结果为0 1000 0001 010 0000 0000 0000 0000 0000 16进制为0x40 a0 00 00

第三章:程序的机器级表示

总纲

当做一门新的语言来,但是是一门贴近硬件的底层语言,在应用过程中加深对底层架构的理解。像硬件应用开发一样,直接操作寄存器,内存。

MIPS的汇编

3.0.1 汇编基本概念

  • 汇编: 把汇编语言翻译为机器语言的过程
  • 汇编程序:实现汇编过程的软件程序
  • 指令: 计算机能执行的代码的最小单位
  • 程序: 指令的有序组合
  • 指令集: 计算机能执行的所有的指令的集合

3.0.2 常用指令集和(复习用)

3.0.3 数据储存方式

  • 数据存放采取字节对齐: 半字类型数据从偶地址开始存放,字类型从4的整数倍地址开始存放
  • 由于为精简指令集,指令长度都为32位即占用4个储存单元(每个储存单元8个bit见2.1.1字节),所以指令地址后两位都相同,这在跳转指令中需要尤其注意.

3.0.4 指令编码分类

这里很容易理解指令集中各个指令属于哪一类的指令码,以下三类指令格式的不同,表明了其在微处理器的实现过程中操作的硬件设施的不同,主要由这里的op与funct字段决定.这里会详解 如何根据需要汇编指令写出其二进制表示

  • R型指令:仅具有寄存器操作数的指令

    一般格式为

op rs rt rd shamt funct
6位 5位 5位 5位 5位 6位
操作码,表明指令基本功能 第一个源操作数寄存器的编码 第二个源操作数寄存器的编码 目的操作数寄存器的编码 位移指令的移位次数编码 功能码,确定op决定指令的详细功能

实例:

  • I型指令:含有立即操作数的指令

    一般格式为

实例:

  • J型指令:无条件跳转指令

    一般格式

3.0.5 指令详解–数据传递

3.0.6 指令详解–算术运算与逻辑运算

3.0.7 指令详解–控制指令

3.0.8 子程序调用

3.0.9 寻址与寻令

3.0.10 宏汇编–程序段解释与一些新的指令的讲解


3.2 程序编码 – 一段汇编码的实例与浅析

你可能感兴趣的:(计算机系统)