计算机组成原理
第一卷 计算机系统概述
第一章 计算机系统层次结构
-
硬件
运算器+存储器+控制器+输入+输出 -
软件
- 系统软件
操作系统、数据库管理系统、语言处理程序、分布式软件系统、网络软件系统、标准库语言、服务性程序 - 应用软件
科学计算类程序、工程设计类程序、数据统计与处理程序
- 系统软件
-
翻译程序
翻译程序 | 应用 |
---|---|
编译器 | 高级语言转机器语言或汇编语言 |
汇编器 | 汇编语言转机器语言 |
解释器 | 源程序转机器指令并立即执行 |
第二章 计算机性能指标
- 主频 CPU工作受主时钟控制,主时钟的频率称为主频,主频的倒数为CPU时钟周期。
:wink:时钟频率的提高,不能保证CPU执行速度又同倍速的提高,有时候还会减慢。
-
CPU执行时间 :表示CPU执行程序占用CPU的时间
-
CPI(Cycle Per Instruction) 执行在计算机体系结构中一条指令所需要的平均时钟周期数
CPI = 执行某段程序所需的 CPU 时钟周期数 / 程序包含的指令条数
-
IPC:(instruction per clock) 表示每(时钟)周期运行多少个指令.
-
MIPS:Million Instruction Per Second,每秒执行百万条指令数,为计算机运算速度指标的一种计量单位。
第二卷 运算系统
这一部分让我们来回归计算机的本职——计算,看看计算机最基本的计算操作是怎么实现的。
第一章 二进制表示
先来复习一下二进制的表示
-
原码 基本的10表示只能表示无符号数,那么负数怎么表示呢,人们想到用0表示真,1表示负。
:wink:由于10000000的意思是-0,这个没有意义,所有这个数字被用来表示-128,所有负数就比正数多一个。 -
反码 正数与原码相同,负数符号位不变,其余反转,反码没有太大实际意义,只是下一位补码的过渡,引入反码后,发现正负数可以相加了,但会有1的偏差。
-
补码就是把偏差的1补上,实现正负数的加法。
11111111 # -1
00000001 # +1:wink:由其原码低位向高位找到第一个1,1和其低位不变,1前面的高位按位取反即可。
接下来我们来会议一下我们之前的高级程序语言中的数据变量,并在这个时候体会设计他们的必要性。
- int 整型变量 占用32位存储,首位为符号位,以补码的形式存储。
- float 浮点型变量 计算机存储小数时如何存储小数点呢?肯定需要在整形的基础上记录一下小数点在哪里,这时一个经典的计数方法正好使用——科学计数法。
第二章 整数加法器
- :question:整数加法器要如何优化,性能瓶颈在哪里。
超前进位,分组进位
第三章 整数减法器
第四章 整数乘法器
- :question:如何从时间角度优化乘法器。
- :question:如何从空间角度优化乘法器。
- 压缩寄存器
- 复用寄存器
- 减小位宽
第五章 整数除法器
第六章 浮点运算
浮点数的标准
:wink:IEEE754
IEEE754即运用了科学计数法的形式表示
第七章 逻辑运算
第三卷 存储系统
SRAM和DRAM
Cache
提高Cache性能
1.全相连模式和组相联模式
- e.g:对于一个32位地址的直接映射的cache设计,下面地址用来访问cache
标记 | 索引 | 偏移量 |
---|---|---|
31-10 | 9-5 | 4-0 |
- Cache 块大小是多少
- answer:wink:因为是32位存储地址,此题也说了是直接映射,因此偏移量是多少,块中每个元素就是多少,因此块大小为32bit,即一字。
- cache有多少项?
- 这个问题就是在问Cache有多少组,cache的索引长度为五位,索引长度即Cache长度,因此Cache长度32项。
- 这样的cache执行时所需要的总位数和数据存储总位数比为多少
下表记录了Cache访问的字节地址
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 4 | 16 | 132 | 232 | 160 | 1024 | 30 | 140 | 3100 | 180 | 2180 |
- cache中多少块被替换
- 这个问题需要把以上地址整除32,除数再整除32,得到的结果即为Cache中的索引。
如 132=32*4+4 因此132占用了Cache中第四个块
依次类推
0=320+0
4=320+4(Cache hit)
16=320+16(Cache hit)
132=324+4
232=327+8
160=325+0
1024=3232+0(Cache rep)
30=320+10(Cache rep)
140=324+12
3100=32(323)+28(Cache rep)
180=325+20(Cache hit)
2180=(32*2+4)*32+24 (Cache rep)
Cache中有两个块发生四次替换
- cache命中率
Cache命中率达到1/4
6. 列出Cache的最终状态,每个有效项以记录的形式<索引,标记,数据>的方式储存
使用多级Cache
- eg.通常来说,cache访问时间与cache容量成正比。假设访问主存需要70ns,并且在所有指令中,36%的指令需要访存,下表是P1,P2两个处理器各自的一级Cache的数据
一级Cache容量 | 一级Cache缺失率 | 一级Cache命中时间 | |
---|---|---|---|
P1 | 2kb | 8% | 0.66ns |
P2 | 4kb | 6% | 0,90ns |
- 假定一级Cache命中时间决定了P1和P2的周期时间,求他们各自的时钟频率
- 时钟频率为 1.5GHZ,1.1GHZ
- P1和P2的平均存储器访问时间分别是多少
- 假定在没有任何存储器阻塞时基本的CPI为1.0,p1,p2各自的CPI为多少
的效率更高
4.在上述基础上,新增二级Cache
二级Cache容量 | 二级Cache 缺失率 | 二级Cache 命中时间 |
---|---|---|
1MB | 95% | 5.62ns |
新增二级缓存后 PI的AMAT为5.946,效率提高。
第四卷 指令系统
第一章 指令格式
- Q1 什么是指令
指令(又称机器指令): 是指示计算机执行某种操作的命令,是计算机运行的最小功能单位。
一条指令就是机器语言的一个语句,它是一组有意义的二进制代码。
一台计算机的所有指令的集合构成该机的指令系统,也称为指令集。
简单说,计算机指令其实就是一种约定好的有意义的信号,比如100100011101……计算机可以从这种信号中执行某些操作。
- 指令组成结构
一条指令最起码需要操作码和地址码两部分结构- 操作码字段告诉计算机做什么操作地址码
- 地址吗告诉计算机对谁操作
一条语句更加具体的样子是这样的
这里地址码分为了4部分:其中,A1和A2地址代表的是要操作的对象在哪;A3代表运算存放的结果在哪;A4表示这条指令执行要执行的下一条指令在哪?
MIPS指令的组成主要有以下三种:
R格式(寄存器格式)
字段 | 位数 | 说明 |
---|---|---|
opcode |
6 | 操作码,通常为0表示R类型指令 |
rs |
5 | 第一个源寄存器 |
rt |
5 | 第二个源寄存器 |
rd |
5 | 目标寄存器,用于存储结果 |
shamt |
5 | 移位量,用于移位指令 |
funct |
6 | 功能码,指定具体的操作类型 |
示例:add $t0, $t1, $t2
opcode
= 0rs
= 9 ($t1
)rt
= 10 ($t2
)rd
= 8 ($t0
)shamt
= 0funct
= 32(add
的功能码)
编码形式:000000 01001 01010 01000 00000 100000
I格式(立即数格式)
字段 | 位数 | 说明 |
---|---|---|
opcode |
6 | 操作码,指定具体的操作类型 |
rs |
5 | 源寄存器 |
rt |
5 | 目标寄存器 |
imm |
16 | 立即数或偏移量 |
示例:addi $t0, $t1, 10
opcode
= 8(addi
的操作码)rs
= 9 ($t1
)rt
= 8 ($t0
)imm
= 10
编码形式:001000 01001 01000 0000 0000 0000 1010
J格式(跳转格式)
字段 | 位数 | 说明 |
---|---|---|
opcode |
6 | 操作码,指定具体的跳转操作类型 |
address |
26 | 跳转地址 |
示例:j 0x00400000
opcode
= 2(j
的操作码)address
= 0x00400000 >> 2(跳转地址右移2位)
编码形式:000010 00000000010000000000000000
总结表
指令类型 | 字段名称 | 位数 | 说明 |
---|---|---|---|
R格式 | opcode |
6 | 操作码,通常为0表示R类型指令 |
rs |
5 | 第一个源寄存器 | |
rt |
5 | 第二个源寄存器 | |
rd |
5 | 目标寄存器,用于存储结果 | |
shamt |
5 | 移位量,用于移位指令 | |
funct |
6 | 功能码,指定具体的操作类型 | |
I格式 | opcode |
6 | 操作码,指定具体的操作类型 |
rs |
5 | 源寄存器 | |
rt |
5 | 目标寄存器 | |
imm |
16 | 立即数或偏移量 | |
J格式 | opcode |
6 | 操作码,指定具体的跳转操作类型 |
address |
26 | 跳转地址 |
第二章 MIPS基本指令
寄存器 | 编号 | 用途 |
---|---|---|
$zero | 0 | 永远为零 |
$at | 1 | 汇编器临时寄存器 |
$v0-v1 | 2-3 | 函数返回值寄存器 |
$a0-a3 | 4-7 | 函数参数寄存器 |
$t0-t7 | 8-5 | 临时寄存器 |
$s0-s7 | 16-23 | 保存寄存器 |
$t8-t9 | 24-25 | 更多临时寄存器 |
$k0-k1 | 26-27 | 内核保留寄存器 |
$gp | 28 | 全局指针 |
$sp | 29 | 栈指针 |
$fp | 30 | 帧指针 |
$ra | 31 | 返回地址寄存器 |
指令 | 功能 | 说明 | 示例 |
---|---|---|---|
lw |
从内存加载一个字到寄存器 | 将内存地址($rs + offset) 处的32位数据加载到寄存器$rt |
lw $t0, 4($sp) |
sw |
将一个字从寄存器存储到内存 | 将寄存器$rt 中的32位数据存储到内存地址($rs + offset) 处 |
sw $t0, 8($sp) |
li |
将一个立即数加载到寄存器 | 将立即数imm 加载到寄存器$rt |
li $t0, 10 |
add |
将两个寄存器的值相加 | 将$rs 和$rt 的值相加,结果存储在$rd |
add $t0, $t1, $t2 |
addi |
将一个寄存器的值和一个立即数相加 | 将$rs 的值和立即数imm 相加,结果存储在$rt |
addi $t0, $t1, 5 |
sub |
将两个寄存器的值相减 | 将$rs 和$rt 的值相减($rs - $rt ),结果存储在$rd |
sub $t0, $t1, $t2 |
and |
对两个寄存器的值进行按位与运算 | 将$rs 和$rt 的值进行按位与运算,结果存储在$rd |
and $t0, $t1, $t2 |
or |
对两个寄存器的值进行按位或运算 | 将$rs 和$rt 的值进行按位或运算,结果存储在$rd |
or $t0, $t1, $t2 |
sll |
将寄存器的值左移指定的位数 | 将$rt 的值左移shamt 位,结果存储在$rd |
sll $t0, $t1, 2 |
beq |
如果两个寄存器的值相等,则跳转 | 如果$rs 的值等于$rt 的值,则跳转到label |
beq $t0, $t1, L1 |
bne |
如果两个寄存器的值不等,则跳转 | 如果$rs 的值不等于$rt 的值,则跳转到label |
bne $t0, $t1, L1 |
j |
无条件跳转到指定的标签 | 无条件跳转到label |
j L1 |
jal |
跳转到指定的标签并将返回地址存储 | 跳转到label ,并将下一条指令的地址存储在$ra 中 |
jal func |
jr |
跳转到寄存器中存储的地址 | 跳转到寄存器$rs 中存储的地址 |
jr $ra |
slt |
如果第一个寄存器的值小于第二个值 | 如果$rs 的值小于$rt 的值,则将$rd 设置为1,否则为0 |
slt $t0, $t1, $t2 |
slti |
如果寄存器的值小于立即数 | 如果$rs 的值小于立即数imm ,则将$rt 设置为1,否则为0 |
slti $t0, $t1, 10 |
第三章 MIPS指令寻址
寻址方式总结
寻址方式 | 解释 | 示例 |
---|---|---|
立即数寻址 | 指令中直接包含操作数(立即数) | addi $t0, $t1, 10 |
寄存器寻址 | 操作数存储在寄存器中 | add $t0, $t1, $t2 |
基址寻址 | 使用基址寄存器和偏移量计算内存地址 | lw $t0, 4($t1) |
PC相对寻址 | 使用当前PC和偏移量计算跳转目标地址 | beq $t0, $t1, label |
伪直接寻址 | 将指令中的目标地址和当前PC的高位组合来形成完整跳转地址 | j target |
第三章 指令集
第五卷 中央处理器
第一章 单周期CPU(简单机)
第二章 流水线
第三章 流水线冒险
结构冒险
-【1】存储器发生结构冒险(存、取冲突)
该操作需要对存储器进行存数据与取指令操作。如图所示,按流水线执行时,第一个周期需要存数据的时候,第四个周期需要进行取指令操作,如果将数据与指令放在同一个存储器中那么就会发生结构冒险。
解决方法
:wink: 所以我们有不同的存储器进行操作,分为指令存储器和数据存储器。
数据冒险
无法提供指令所需数据而导致指令不能在预定的时钟周期内执行的情况。即一条指令的执行需要等待另一条指令执行完成后所产生的数据。
- 阻塞解决
- 旁路解决
前推(Forwarding):也叫旁路,是从内部寄存器而非程序员可见的寄存器或存储器中提前取出数据。(前推是根据顺序所起的名字,旁路是根据结构所起的名字。)
三条前推路径
-
bullet∙ 在EX阶段结尾可以取出ALU的运算结果,无需写回;
-
bullet∙ 在MEM阶段结尾可以取出ALU的运算结果,无需写回;
-
bullet∙ 在MEM阶段结尾可以取出memory的结果,无需写回;
分支冒险