Day1

第1节:计算机层次结构

计算机本质

1
2
3
4
5
输入

处理

输出

计算机系统的层次结构

1
2
3
4
5
6
7
8
9
应用程序

操作系统

指令系统(ISA)

硬件


第一层:应用软件

例如QQ,微信等

第二层:操作系统

windows等,用于管理硬件资源

比如cpu,内存,磁盘,网络等等都由操作系统统一管理

第三层:ISA

ISA:(Instruction Set Architecture)指令集体系结构

本质是软件和硬件之间的接口

cpu只认识ADD,MOV,SUB,JMP这样的机器指令

而Java代码需要

1
2
3
4
5
6
7
Java

字节码

机器指令

CPU

最终都要变成 ISA 规定的指令

同一个代码在不同品牌cpu生成的机器码可能不同

x86代表:Intel和AMD

指令复杂
性能强
功耗高

ARM代表:手机CPU,平板CPU

指令简单
省电
效率高

翻译过程

1
int a = 1 + 2;

会经历:

1
2
3
4
5
6
7
8
9
10
11
Java代码

编译器

字节码

JVM

机器指令

CPU执行

CPU最终看到的可能是:

1
2
MOV EAX,1
ADD EAX,2

第2节:冯诺依曼体系结构

冯诺依曼五大部件

输入设备:把信息送入计算机(鼠标,键盘等)
输出设备:把结果显示给用户(显示器,打印机,音响)
存储器:存程序,存数据(内存)
运算器:进行加减乘除等各种运算(核心:ALU算数逻辑单元)
控制器:控制整个cpu工作,负责取指令,分析指令和执行指令

cpu组成

CPU主要由运算器和控制器组成。

运算器负责算术逻辑运算,
控制器负责取指、译码和控制执行。

1
2
3
CPU
├── 运算器(ALU)
└── 控制器(CU)

存储程序思想

核心思想:程序和数据统一存放在存储器中

以前:

程序一块
数据一块

现在:

内存里全都有,CPU从存储器取指执行

第3节:性能指标

什么是主频

含义:CPU每秒振动多少次

例如:

1
2
3
4
5
1 GHz
=
10^9 Hz
=
10亿次/秒

即:1秒钟产生10亿个时钟周期

什么是时钟周期

主频和时钟周期互为倒数

主频 时钟周期
1GHz 1ns
2GHz 0.5ns
4GHz 0.25ns

什么是CPI

平均每条指令需要多少个时钟周期

例如:

CPU执行ADD需要1个周期,执行MUL需要3个周期

那么平均下来:CPI≈2

CPI越小执行越快

1
2
3
4
5
CPU时间
=
指令数
× CPI
× 时钟周期

Day2

ALU

(Arithmetic Logic Unit)算术逻辑单元,用于处理算数运算(加减乘除)和逻辑运算(与或非)

AND
OR
NOT
XOR(异或,相同0不同1,符号为^)

1
2
3
A ^ A = 0

A ^ 0 = A

ALU计算时不会直接从内存拿数据,会先放到寄存器(速度最快)

1
2
3
4
5
6
7
8
9
内存

寄存器

ALU

寄存器

内存

普通加法器一般是串行进位加法器

串行进位加法器中,每一位的进位依赖低一位的进位,进位需要逐级传递,因此速度较慢。

sub实现:A - B = A + (~B) + 1

先行进位

先行进位就是:不等低位慢慢传,而是提前算出各位进位。

两个信号:

进位产生信号 G
进位传递信号 P

半加器

半加器处理:

1
2
3
A
+
B

输出:

1
2
S(和)
C(进位)
A B S C
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1

S = A ^ B

C = A & B

S=A⊕B

C=A⋅B

但是半加器不能处理A+B+进位情况

全加器

输入:

1
2
3
A
B
Cin

其中:

1
Cin=上一位传来的进位

输出:

1
2
S
Cout

和:

1
S=A^B^Cin

进位:

1
2
3
4
只要三个输入中
有两个以上是1

就产生进位

CPU加法就是多个全加器串联实现多位二进制加法。

溢出

8位补码范围:-128 ~ +127

最大正数:

1
01111111

=127


最小负数:

1
10000000

=-128

127+1=-128,溢出

看同号相加的结果,结果变号就会溢出

源码反码补码

正数:原码 = 反码 = 补码

负数:
原码:符号位为1,数值位正常写
反码:符号位不变,数值位取反
补码:反码 + 1

定点数和浮点数

定点数就是小数点位置固定的数,常用于表示整数或固定精度的小数

浮点数就是小数点位置可以浮动的数(不同的数,可以通过不同的阶码,让小数点浮动到不同位置。)

组成:

1
2
3
4
5
符号位 + 阶码 + 尾数

//符号位:表示正负
//阶码:表示小数点移动多少位
//尾数:表示有效数字

可以理解成科学计数法:

1
123.45 = 1.2345 × 10²

在计算机里类似:

1
尾数 × 基数^阶码

基数为2时,比如1.01 × 2^3,表示把这个二进制小数点往右移动 3 位

浮点数在数轴上的分布不均匀。由于尾数位数有限,阶码越大,相邻两个可表示数之间的间隔越大,所以越远离原点越稀疏。

负定点小数补码

求 -0.1011 的补码

第一步:写原码

1
-0.1011 原码 = 1.1011

第二步:除符号位外取反

小数部分:

1
1011

按位取反:

1
0100

所以反码:

1
1.0100

第三步:末位加 1

1
2
3
1.0100
+0.0001
=1.0101

所以:

1
-0.1011 的补码 = 1.0101

正数:原码 = 反码 = 补码

机器补码浮点数加减

  1. 先对阶,小阶向大阶看齐。
  2. 把尾数写成补码。
  3. 尾数补码相加。
  4. 判断结果是否规格化。
  5. 不规格化就移动尾数,同时调整阶码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
已知:
x = 2^101 × 0.11011011
y = 2^111 × (-0.10101100)

条件:

1. 尾数用补码表示;
2. 可存储 10 位尾数;
3. 尾数含 2 位符号位,即双符号位;
4. 阶码用补码表示。

求:
x + y



因为尾数有 双符号位,正数尾数前面写 00.,负数尾数前面写 11.

[x]浮 = 00 101,00.11011011
[y]浮 = 00 111,11.01010100

对阶:
Ex - Ey = 101 - 111 = -2,所以 Ex < Ey,小阶向大阶看齐。
x 阶码加 2,x 尾数右移 2 位:

[x]浮 = 00 111,00.00110110(11)

尾数相加:
00.00110110(11)
+ 11.01010100
= 11.10001010(11)


结果非规格化,尾数左规 1 位,阶码减 1:
00 110,11.00010101(1)
//正数规格化:00.1xxxxxxx
//负数规格化:11.0xxxxxxx

舍入(0 舍 1 入):
00 110,11.00010110



规则:尾数相加后:

1. 如果双符号位不同:01.xxx 或 10.xxx
→ 说明尾数溢出
→ 右规:右移 1 位,阶码 +1

2. 如果双符号位相同,但不符合规格化:
正数不是 00.1xxx
负数不是 11.0xxx
→ 说明尾数绝对值太小
→ 左规:左移,阶码 -1

(阶码)无溢出。

所以:
[x+y]浮 = 00 110,11.00010110

真值为:
x+y = 2^110 × (-0.11101010)₂

校验码

校验码是用来检查数据在传输或存储过程中有没有出错的。

奇偶校验码

奇偶校验就是:在原数据后面加 1 位校验位,让 1 的个数满足奇数或偶数。

偶校验要求整个码字中 1 的个数是偶数,奇校验要求整个码字中 1 的个数是奇数。

作用:

能发现奇数个位出错

CRC 校验码(循环冗余校验码)

CRC 校验通过约定生成多项式,对数据进行模 2 除法,将余数作为校验码附加在数据后。接收方再次进行模 2 除法,若余数为 0,则认为没有检测到错误;若余数不为 0,则说明数据出错。

检错能力强,特别适合检测突发错误

例题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
100011

1. 采用偶校验,校验位是多少?
2. 若采用 CRC,生成多项式 G(x) = x^3 + 1,生成多项式对应的二进制是多少?
3. CRC 校验码是几位?



1. 奇偶校验
数据:
100011
里面有 3 个 1。
偶校验:要求总的 1 个数为偶数,现在是 3 个,所以补 1。
偶校验位 = 1
奇校验:要求总的 1 个数为奇数,现在已经是 3 个,所以补 0。
奇校验位 = 0



2. CRC 校验
生成多项式
G(x) = x³ + 1 = 1001
最高次是 3,所以原数据后面补 3 个 0:
100011000
做模 2 除法:(要一直除到“剩下的位数比除数少”为止)
100011000 ÷ 1001
余数为:
111
所以:
CRC 校验码 = 111
发送码字 = 100011111

Day3

存储器层次结构

又快到慢(容量由小到大):

1
2
3
4
5
6
7
8
9
寄存器(Register)

Cache

主存(内存)

SSD(固态硬盘)

机械硬盘

寄存器:位于cpu内部,最快,最贵,最小,容量几十到几百字节

Cache(缓存):位于cpu和内存之间,作用是减少cpu的等待时间(CPU速度远高于内存)

内存:存放int a的a

磁盘:不像内存断电即失,电脑关机后数据仍然存在

局部性原理

时间局部性

刚访问过的数据,很快还会再次访问

eg:

1
2
3
for(int i=0;i<10000;i++){
sum+=a;
}

变量a被重复访问,cpu会放进缓存而不是每次都从内存中取

空间局部性

访问一个地址后

附近地址
大概率也会访问

数组:

1
int arr[100];

遍历:

1
2
3
for(int i=0;i<100;i++){
sum+=arr[i];
}

访问:

1
arr[0]

后面大概率:

1
2
3
arr[1]
arr[2]
arr[3]

因此cpu访问arr[0]时缓存会把后面的一整块都加载出来(Cache Line)

命中与缺失

需要的数据缓存里面有则Cache Hit

没有则Cache Miss

命中率:

Hit Rate=命中次数/总访问次数

Cache映射方式

直接映射

一个内存块,只能放一个固定位置

1
2
3
4
5
6
7
8
9
10
11
内存块0 → Cache0

内存块1 → Cache1

内存块2 → Cache2

内存块3 → Cache3

内存块4 → Cache0

内存块5 → Cache1

取模来分配

优点:简单,速度快

缺点:有冲突,内存块会不断覆盖

直接映射的地址格式是:

1
| 标记 Tag | Cache 行号 Index | 块内地址 Offset |

题目说主存容量多少,就用 log2(主存容量) 求地址位数。

块内地址位数offset = log₂(块大小)

Cache 行数 = Cache 数据容量 / 块大小
Index 位数 = log₂(Cache 行数)

Tag = 主存地址位数 - Index - Offset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
eg:

主存地址 32 位,Cache 数据容量 64KB,块大小 16B,直接映射。
问:主存地址如何划分?



块大小(每行的数据大小) 16B = 2⁴B,所以 Offset = 4 位。

Cache 行数 = 64KB / 16B
= 2¹⁶ / 2⁴
= 2¹² 行,所以 Index = 12 位。

Tag = 32 - 12 - 4 = 16 位。

所以:| Tag 16位 | Index 12位 | Offset 4位 |

全相联映射

任何内存块,可以放Cache任意位置

优点:冲突最少。
缺点:硬件复杂,需要同时比较很多 Tag。

| Tag | Offset |

不用指定 Cache 第几行,任意行都能放。

组相联映射

例如:

4个Cache位置。

分成:

1
2
3
4
5
第0组
Cache0 Cache1

第1组
Cache2 Cache3

内存块确定组,然后组内任意放

| Tag | 组号 Index | Offset |

关联度:每组有多少行,关联度越高,每个主存块可选择的位置越多,冲突越少,但硬件越复杂。

关联度越高

组数越少

Index 位数越少

Tag 位数越多

现代CPU常用组相联:组相联在命中率和实现复杂度之间取得平衡。

计算

1
2
3
4
5
Cache 行数 = Cache 数据容量 / 块大小
组数 = Cache 行数 / 关联度
Offset = log₂(块大小)
Index = log₂(组数)
Tag = 主存地址位数 - Index - Offset

对比

映射方式 地址格式 特点
直接映射 Tag + 行号 Index + Offset 最简单,冲突最多
全相联 Tag + Offset 冲突最少,硬件最复杂
组相联 Tag + 组号 Index + Offset 折中方案,常用

Cache 容量计算

Cache 数据容量 = Cache 行数 × 每行数据大小

Cache 总容量:

除了数据,还要存一些附加信息

Cache 总容量 = 行数 × (数据位数 + Tag 位数 + 有效位 + 脏位)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
主存容量:1024MB
Cache 数据容量:8KB
块大小:32B
映射方式:直接映射
每行有 1 位 Valid
访问地址:0x0C63B


1. 主存地址一共多少位? 1024MB = 1GB = 2^30 B 30
2. 块内地址 Offset 多少位? 32B = 2^5 B 5
3. Cache 行号 Index 多少位? 8KB / 32B= 2^8 行
4. Tag 多少位? 30 - 8 - 5=17位
5. 地址 0x0C63B 的 Tag / Index / Offset 分别是多少?
6. Cache 总容量是多少 bit?只算 Data + Tag + Valid。 (256(bit) + 17 + 1)*256



5.
因为题目主存地址是 30 位,所以要把地址写成 30 位二进制。
0x0C63B
= 0000 1100 0110 0011 1011

这是 20 位,不够 30 位,所以左边补 0:
0x0C63B = 000000000000001100011000111011

按照地址格式:
| Tag 17位 | Index 8位 | Offset 5位 |

从右往左切:
00000000000000110 | 00110001 | 11011
Tag | Index | Offset

所以:
Tag = 00000000000000110 = 0x6
Index = 00110001 = 0x31
Offset = 11011 = 0x1B

十进制为:
Tag = 6
Index = 49
Offset = 27


虚拟存储器

物理地址:真实内存位置

虚拟地址:程序看到的地址(不一定存在)

cpu访问虚拟地址,系统再转化为物理地址

为了方便管理,内存被切成了很多小块,每一块叫页

页表:记录虚拟页与物理页的对应关系

TLB

TLB 是页表的缓存(保存虚拟页号 VPN → 物理页号 PPN)

因为每次都查页表太慢,所以 CPU 先查 TLB。

地址转换过程

程序:

1
2
3
4
5
6
7
虚拟地址

页表

物理地址

内存

缺页:

程序访问某个虚拟页,页表发现不在内存里面,系统将从磁盘读取把数据调入内存,这个过程叫缺页中断

虚拟存储器作用

1

运行大程序

例如:

1
2
3
程序20GB

内存8GB

仍然能跑。

2

进程隔离

程序A:0x1000

程序B:0x1000

不会冲突。

因为:映射到不同物理地址

3

提高内存利用率

只加载正在使用的页。

VPN / VPO / PPN / PPO 地址划分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
VA:虚拟地址
PA:物理地址

VPN:虚拟页号
VPO:虚拟页内偏移

PPN:物理页号
PPO:物理页内偏移


虚拟地址 VA = VPN + VPO
物理地址 PA = PPN + PPO

VPO = PPO(虚拟地址转换成物理地址时,变的是“页号”,但页内位置不变)

页内偏移位数 = log₂(页大小)

比如:页大小=8KB = 8192B = 2¹³B,VPO = PPO = 13 位

VPN = 虚拟地址位数 - VPO

PPN = 物理地址位数 - PPO

完整访问流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
CPU 产生虚拟地址 VA

VA 分成 VPN + VPO

查 TLB

┌───────────────┐
│ TLB 命中? │
└───────────────┘
↓是 ↓否
得到 PPN 查页表
↓ ↓
形成 PA ┌───────────────┐
│ 页在内存中? │
└───────────────┘
↓是 ↓否
得到 PPN 缺页中断
↓ ↓
更新 TLB 操作系统从磁盘调页
↓ ↓
形成 PA 修改页表/TLB
↓ ↓
└──────重新形成 PA

访问 Cache

┌───────────────┐
│ Cache 命中? │
└───────────────┘
↓是 ↓否
返回数据 访问主存

调入 Cache

返回数据

Day5

指令格式

基本指令格式

指令的构成:操作码 + 地址码

操作码:

操作码 含义
ADD 加法
SUB 减法
MOV 数据传送
LOAD 从内存取数据
STORE 把数据存入内存
JMP 跳转

三地址指令:

ADD R1, R2, R3 R1 = R2 + R3

二地址指令:

ADD R1, R2 R1 = R1 + R2

一地址指令:

ADD X ACC = ACC + X(默认有一个操作数在 ACC 累加器里)

零地址指令:

没有显式地址码,常用于栈结构

例如栈里有两个数:

1
2
栈顶:3
下面:5

执行:

1
ADD

结果为8

具体指令格式

R 型指令

1
| op | rs | rt | rd | shamt | funct |
字段 位数 作用
op 6 位 操作码,表示指令大类
rs 5 位 第一个源寄存器
rt 5 位 第二个源寄存器
rd 5 位 目标寄存器,也就是结果写到哪里
shamt 5 位 移位位数,shift amount
funct 6 位 功能码,进一步说明具体是哪条 R 型指令

I 型指令

1
| op | rs | rt | immediate |

J型指令

1
| op | target |

例题:

设计地址字段:20位地址总线,80条指令,四种寻址方式,怎么设计

操作码 OP = 7 位,寻址方式字段 = 2 位

所以:| OP 7位 | 寻址方式字段 2位 | 地址字段 A 20位 |

扩展:| OP 7位 | 寻址方式 2位 | 地址字段 20位 | 保留/扩展 3位 |

扩展操作码

扩展操作码是在指令字长固定的情况下,根据不同指令所需地址码个数不同,采用不同长度的操作码。地址码多的指令使用较短操作码,地址码少的指令使用较长操作码,以提高指令编码空间利用率,并要求译码唯一。

地址码越多,操作码越短,单条指令功能越完整,程序指令条数越少。

地址码越少,操作码越长,隐含操作数越多,完成同样任务所需指令条数越多。

类型 指令格式 地址码个数 操作码长度 指令条数 特点
三地址指令 OP A1 A2 A3 3 个 最短 最少 一条指令能说明两个源操作数和一个结果地址
二地址指令 OP A1 A2 2 个 比三地址长 比三地址多 一个地址既是源操作数又是结果地址
一地址指令 OP A 1 个 更长 更多 另一个操作数通常隐含在累加器 ACC 中

要区分指令条数和指令位数(MIPS是32位)!

控制信号

主控制器根据 op 字段产生普通控制信号,如 RegWrite、MemRead、MemWrite、Branch、Jump、ALUSrc 等。

ALU 局部控制器根据 ALUOp 和 funct 字段产生具体 ALU 控制信号,决定 ALU 执行加、减、与、或、比较等操作。

I 型和 J 型指令主要由 op 字段决定控制信号;
R 型指令 op 只说明它是 R 型,具体 add、sub、and、or 等操作还要由 funct 字段决定。

寻址

寻址方式 操作数在哪里 有效地址 EA
立即寻址 指令中 没有 EA
直接寻址 内存中 EA = A(指令中的地址字段)
间接寻址 内存中 EA = M[A]
寄存器寻址 寄存器中 没有 EA(操作数就在寄存器 R 里)
寄存器间接寻址 内存中 EA = R(某个寄存器里存放的地址)
相对寻址 内存中 EA = PC + A
变址寻址 内存中 EA = X(变址寄存器) + A

基址寻址

EA = A + B

详细见https://www.liziling-blog.top/2026/05/11/%E6%B1%87%E7%BC%96/

RISC 和 CISC

RISC 是精简指令集计算机,指令数量少,格式固定,寻址方式少,大多数指令能在一个周期内完成,硬件控制简单,适合流水线。

CISC 是复杂指令集计算机,指令数量多,功能复杂,指令长度不固定,寻址方式多,硬件控制复杂,单条指令可以完成较复杂的操作。

RISC 的典型代表是 ARM、MIPS、RISC-V;CISC 的典型代表是 x86。

Day6

CPU 关键寄存器

寄存器 作用 补充说明(帮助理解)
PC 存放下一条指令的地址 每次取指后会自动更新,指向下一条指令,PC = PC + 4
IR 存放当前正在执行的指令 取出的指令代码放在这里,供指令译码器解析具体要执行什么操作。
MAR 存放要访问的内存地址 CPU 读写内存前,必须先把目标地址放到这里,从而打通与地址总线的连接。
MDR 存放从内存读出或写入内存的数据 它是 CPU 与内存进行数据交换的“中转站”,直接与数据总线相连。
ACC 暂存运算结果 一地址指令中,ACC 经常是默认操作数
PSW 保存状态标志 记录运算后的状态(如进位CF、溢出OF、结果为零ZF等),供后续的条件转移指令使用。

取指周期

CPU 执行程序时,第一步一定是:从内存中取出下一条要执行的指令

流程:

  1. PC → MAR
  2. M[MAR] → MDR
  3. MDR → IR
  4. PC + 4 → PC

指令执行过程

1
2
3
4
5
6
7
8
9
取指

译码

取操作数

执行

写回结果

取指:上一节内容,就是把下一条指令从内存取出来,放到 IR

译码:分析 IR 里的指令

取操作数:CPU 需要把参与运算的数据取出来

执行:ALU或其他器件真正完成操作

写回结果:把执行结果写回指定位置

对应到硬件上就是:

  • PC:保存当前指令地址。
  • IR:保存取出的指令。
  • 寄存器堆:读 rs、rt,写 rd 或 rt。
  • ALU:做加减、逻辑运算、地址计算、比较。
  • 存储器:读指令、读写数据。
  • 控制器:根据 opcode / func 产生控制信号。

控制器

作用:指挥 CPU 各个部件按顺序工作

控制信号:就是控制器发出的命令

两种控制器

对比 硬布线控制器 微程序控制器
实现方式 逻辑电路直接产生控制信号 通过微指令产生控制信号
速度 较慢
修改难度 修改困难 修改方便
设计复杂度 电路复杂 结构规整
适合 RISC CISC

微程序

微命令:最基本的控制信号
微指令:一组微命令的集合
微程序:完成一条机器指令的一串微指令

控制存储器:存放微程序的存储器
微地址:微指令在控制存储器中的地址
下址字段:指出下一条微指令地址

一条机器指令对应一段微程序,一段微程序由多条微指令组成,一条微指令包含多个微命令。

Day7

流水线

流水线执行方式是:多条指令重叠执行

经典五级流水线:

1
2
3
4
5
IF:取指
ID:译码
EX:执行
MEM:访存
WB:写回

image-20260622135555901

5级流水线执行4条指令
= 5 + 4 - 1
= 8 个周期

加速比 = 非流水线执行时间 / 流水线执行时间

流水线冲突

类型 本质 例子 解决方法
结构相关 抢硬件资源 两条指令同时访存 增加硬件、暂停
数据相关 等前面结果 后一条用前一条结果 数据转发、暂停
控制相关 分支跳转不确定 if/跳转指令 分支预测、暂停

分支预测:让cpu猜会不会跳转,猜对了继续,猜错了清空错误指令重新取正确指令

I/O 控制方式

程序查询方式

1
2
3
4
5
6
7
8
9
CPU 查询设备状态

没准备好

继续查询

还没准备好

继续查询

中断方式

1
2
CPU 先去干别的事
设备准备好了,再通知 CPU

DMA 方式

外设和内存之间可以直接传数据,不需要 CPU 一个字节一个字节搬运

DMA工作过程:

  1. CPU 设置 DMA 控制器
  2. DMA 控制器接管总线
  3. 外设和主存直接传输数据
  4. 传输完成后,DMA 控制器向 CPU 发出中断
  5. CPU 进行后续处理

通道方式

通道:专门负责 I/O 的小处理器

方式 CPU 参与程度 特点 适合场景
程序查询 最高 CPU 一直等 简单低速设备
中断 较高 设备好了通知 CPU 随机少量数据
DMA 较低 内存和外设直接传输 高速大量数据
通道 更低 专门 I/O 处理器控制 大型复杂系统

中断

流程:

  1. 中断请求
  2. 中断响应
  3. 关中断
  4. 保存断点和现场
  5. 转入中断服务程序
  6. 执行中断服务程序
  7. 恢复现场
  8. 开中断
  9. 返回原程序

断点:原程序下一条要执行的指令地址

现场:就是 CPU 当前的状态(寄存器内容,PSW状态字等等)

Day8

MIPS 指令格式与跳转地址

  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    1. MIPS 属于 RISC 还是 CISC?
    2. MIPS 指令是定长还是变长?
    3. R 型指令格式是什么?
    4. I 型指令格式是什么?
    5. J 型指令格式是什么?
    6. 顺序执行时 PC 怎么变?
    7. beq/bne 分支目标地址怎么算?
    8. j 指令跳转目标地址怎么算?



    1. MIPS 属于 RISC。

    2. MIPS 指令定长,每条指令 32 位。

    3. R型:
    | op(6)| rs | rt | rd | shamt | funct(6)|

    4. I型:
    | op(6) | rs | rt | immediate(16) |

    5. J型:
    | op(6位) | target |

    6. 顺序执行:
    PC ← PC + 4

    7. 分支跳转 beq/bne:
    先比较 R[rs] 和 R[rt]。
    beq 相等跳转,bne 不等跳转。
    目标地址:
    PC ← PC + 4 + SignExt(imm16) << 2

    8. 无条件跳转 j:
    PC ← { PC+4[31:28], target[25:0], 2'b00 }
  2. add:
    R[rd] ← R[rs] + R[rt]

  3. sub:
    R[rd] ← R[rs] - R[rt]

  4. lw:
    R[rt] ← M[R[rs] + SignExt(offset)]

  5. sw:
    M[R[rs] + SignExt(offset)] ← R[rt]

  6. beq:
    如果 R[rs] == R[rt],
    PC ← PC + 4 + (SignExt(offset) << 2)
    否则,
    PC ← PC + 4

  7. bne:
    如果 R[rs] != R[rt],
    PC ← PC + 4 + (SignExt(offset) << 2)
    否则,
    PC ← PC + 4

  8. j:(直接跳)
    PC ← { PC+4[31:28], target[25:0], 2’b00 }

  9. jal:(先把返回地址存到 R31,再跳)
    R[31] ← PC + 4
    PC ← { PC+4[31:28], target[25:0], 2’b00 }

  10. jr:(跳到寄存器里的地址)
    PC ← R[rs]

  11. addi:
    R[rt] ← R[rs] + SignExt(imm16)

  12. ori:
    R[rt] ← R[rs] OR ZeroExt(imm16)

数据通路

它由两类部件组成:

1. 操作部件

比如:

  • ALU
  • 加法器
  • 多路选择器 MUX
  • 符号扩展器 SignExt
  • 零扩展器 ZeroExt

2. 存储部件

比如:

  • PC
  • IR
  • 寄存器堆
  • 数据存储器
  • MDR / MBR
  • 状态寄存器

总规律:

1
2
3
4
5
6
7
PC 给出地址

指令存储器取指令

指令译码

根据指令类型走不同数据通路
1
PC ← PC + 4
指令 类型 读寄存器 ALU 作用 访存 写回 PC 更新
add rd, rs, rt R 型 读 rs、rt 加法 不访存 写 rd PC + 4
sub rd, rs, rt R 型 读 rs、rt 减法 不访存 写 rd PC + 4
lw rt, offset(rs) I 型 读 rs 算地址 读内存 写 rt PC + 4
sw rt, offset(rs) I 型 读 rs、rt 算地址 写内存 不写寄存器 PC + 4
beq rs, rt, offset I 型 读 rs、rt 减法比较 不访存 不写寄存器 相等跳
bne rs, rt, offset I 型 读 rs、rt 减法比较 不访存 不写寄存器 不等跳
j target J 型 不读 rs/rt 不比较 不访存 不写寄存器 无条件跳
指令 类型 读寄存器 ALU作用 访存 写回 PC更新
jal target J型 不读 不用 不访存 $31=PC+4 跳转
jr rs R型 rs 不用 不访存 不写 PC=R[rs]
addi rt,rs,imm I型 rs 加立即数 不访存 rt PC+4
ori rt,rs,imm I型 rs 按位或 不访存 rt PC+4

MIPS控制信号

控制信号 意思
RegDst 选择写哪个寄存器:0写rt1写rd2写$31
ALUSrc ALU 第二个输入:0来自rt1来自立即数
MemtoReg 写回数据来源:0来自ALU1来自内存2来自PC+4
RegWr 是否写寄存器:1写0不写
MemWr 是否写内存:1写内存0不写
Branch 是否分支指令:beq/bne 为1
Bne 是否不等跳:beq为0bne为1
Jump 是否跳转:j/jal/jr 为1
Jal 是否是 jal,要写 $31=PC+4
Jr 是否是 jr,PC 跳到 R[rs]
ExtOp 立即数扩展:0零扩展1符号扩展
ALUOp ALU 做什么:add/sub/or

(算术、地址偏移、分支 → 符号扩展
逻辑运算(andi) → 零扩展)

指令 RegDst ALUSrc MemtoReg RegWr MemWr Branch Bne Jump Jal Jr ExtOp ALUOp
add 1 0 0 1 0 0 0 0 0 0 x add
sub 1 0 0 1 0 0 0 0 0 0 x sub
lw 0 1 1 1 0 0 0 0 0 0 1 add
sw x 1 x 0 1 0 0 0 0 0 1 add
beq x 0 x 0 0 1 0 0 0 0 x sub
bne x 0 x 0 0 1 1 0 0 0 x sub
j x x x 0 0 0 0 1 0 0 x x
jal 2 x 2 1 0 0 0 1 1 0 x x
jr x x x 0 0 0 0 1 0 1 x x
addi 0 1 0 1 0 0 0 0 0 0 1 add
ori 0 1 0 1 0 0 0 0 0 0 0 or

磁盘响应时间计算

磁盘平均存取时间 = 平均寻道时间 + 平均旋转延迟 + 数据传输时间

名称 含义
平均寻道时间 磁头移动到目标磁道所需时间
平均旋转延迟 等目标扇区转到磁头下面的平均时间
数据传输时间 真正读/写数据花的时间

平均旋转延迟 = 磁盘转一圈时间 / 2

数据传输时间 = 要读写的数据量 / 数据传输率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
磁盘扇区大小:512B
转速:5400 RPM(5400 RPM = 每分钟 5400 转)
平均寻道时间:12 ms
数据传输率:4 MB/s
控制器开销:1 ms
不考虑排队时间


1. 一圈时间 = ?
2. 平均旋转延迟 = ?
3. 数据传输时间 = ?
4. 总响应时间 = ?


1.5400 ÷ 60 = 90 转/秒,一圈时间 = 1 / 90 s= 11.11 ms
2.平均旋转延迟 = 11.11 / 2≈ 5.56 ms
3.数据传输时间 = 512 / (4 × 1024 × 1024) s
≈ 0.000122 s
≈ 0.122 ms


4.响应时间 = 12 ms + 5.56 ms + 0.125 ms + 1 ms
= 18.685 ms

存储器扩展设计

  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    用 256K × 8 位 SRAM 芯片
    组成 1MB × 32 位的存储器



    1. 总共需要几片 SRAM?
    2. 位扩展需要几片?
    3. 字扩展需要几组?
    4. 地址线需要多少根?
    5. 数据线需要多少根?



    1. 总片数 = 16 片

    2. 位扩展 = 32 / 8 = 4 片

    3. 字扩展 = 1M / 256K = 4 组

    4. 地址线 = 20 根(1M = 2^20)
    其中 A0 ~ A17 接芯片地址端,
    A18 ~ A19 经译码产生 4 组选通信号。

    5. 数据线 = 32 根(D0~D31)


    地址线方面,目标存储器容量为 1M = 2^20,因此需要 20 根地址线 A0~A19。每片 SRAM 容量为 256K = 2^18,因此低 18 位地址线 A0~A17 接到所有芯片的地址端;高 2 位地址线 A18、A19 经过 2-4 译码器产生 4 个片选信号,用来选择 4 组芯片。

Day9

大小端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
union test {
int a;
char b;
};

test.a = 0x12345678;

if (test.b == 0x12)
printf("大端");
else
printf("小端");


1. union 里 a 和 b 是不是共用同一块内存?
2. 小端存储时,0x12345678 在内存中怎么放?
3. 大端存储时,0x12345678 在内存中怎么放?
4. 如果 test.b == 0x12,说明是大端还是小端?
5. 如果 test.b == 0x78,说明是大端还是小端?


最左边:低地址,高位字节


1. union 中 a 和 b 共用同一块内存。
2. 小端:
低地址 → 高地址(低位字节放低地址)
[78] [56] [34] [12]
3. 大端:
低地址 → 高地址(高位字节放低地址)
[12] [34] [56] [78]
4. test.b == 0x12,说明是大端。
5. test.b == 0x78,说明是小端。

Hello World 开发执行过程

编辑

预处理

编译

汇编

链接

装入内存

CPU 取指、译码、执行

通过系统调用和 I/O 设备输出 hello world

输出:printf → 系统调用 → 操作系统 → 设备驱动 → 显示器

总线

地址总线:传送地址,决定能寻址多大空间。
数据总线:传送数据,决定一次能传多少位。
控制总线:传送读写、中断、时钟、片选等控制信号。