计算机组成原理
1.计算机抽象与相关技术
冯诺依曼架构
运算器、存储器、控制器、输入设备、输出设备
计算机体系结构的7个思想
- 使用抽象简化设计
无论是硬件还是软件都可以抽象成多个层次,每个较低的层次对上层隐藏细节。硬件和底层软件直接的接口--指令集体系结构,使同一软件可以由不同的方法来完成。 - 加速大概率事件
Amdahl定律,加速大概率事件比优化小概率事件更能提高性能。 - 通过并行提高性能
指令级并行,多发射。 - 通过流水线提高性能
通过多级流水线拆分单个指令,实现深度流水,以五级流水线为例,在不阻塞的情况下,一个周期共有五个指令在执行,虽然CPI仍为1,但是时钟周期大幅缩短,提高了指令执行效率。 - 通过预测提高性能
在确定执行什么操作前先进行执行操作,如果出错回滚即可。 - 存储层次
采用多层存储方式,平衡速度、容量、成本。 - 通过冗余提高可靠性
通过冗余部件提升可靠性。
摩尔定律:集成在单芯片上的资源数目每年翻一番。加工成本逐年降低。
对于现代计算机来说必要的两个系统软件
- 操作系统
- 处理基本的输入输出操作
- 分配外存和内存
- 为多个应用程序提供共享计算机资源的服务
- 编译器
将高级语言编写的程序翻译成硬件能执行的指令。(编译器将高级语言翻译为汇编语言,汇编器将汇编语言翻译为机器指令) 在后续的数据冒险和控制冒险中,编译器还用来调整指令执行顺序来加速程序执行速度。
性能
吞吐率、响应时间
一般来说,降低响应时间都会提升吞吐率。当吞吐率达到上限时再提高吞吐率也可以降低响应时间。二者是相互影响的。
考虑执行时间来讲,
=
所有计算机都使用时钟作为定时基准驱动硬件,这种离散的时间间隔称为时钟周期,而时钟周期的倒数称为时钟频率。如4GHz的时钟周期为250ps。
- = =
- =
- (流水线CPU靠压缩时钟周期时间来提升性能)
CPI为每条指令的平均时钟周期数,而IPC为每个时钟周期平均执行的指令数(用于评价多发射).
功耗墙
能耗
功耗
时钟频率增长,但是电压会下降,因此之前功率倍数不会过快增长, 现在电压下降会出现泄露的情况,因此功率难以控制
多处理器
一个四核微处理器包含四个处理器或者四个核的芯片
2.指令:计算机的语言
大小端储存方式
例如0x10000000 存的是0x11223344。如果是大端,则0x10000000存的是0x11,如果是小端,存的则是0x44
主要采用MIPS指令集,MIPS为了方便指令执行,所有指令均为32位,分为R型指令和I型指令。
R型指令:6 opcode操作码 5 rs 5 rt 5 rd 5 shamt移位 6funct I型指令:6 opcode操作码 5 rs 5 rt 16立即数 J型指令:6 opcode操作码 26立即数做地址索引 MIPS指令集有32位寄存器,由于现代架构不止32位寄存器,而MIPS只能看见32位寄存器,后续在进行流水线CPU或多发射时会出现名字相关这种假阻碍程序运行的冒险,需要编译器针对程序进行重命名。
常见MIPS指令:
| 助记符 | 格式 | 示例 | 说明 |
|---|---|---|---|
| add | R型 | add $t1,$t2,$t3 | t1 = t2 + t3 |
| sub | R型 | sub $t1,$t2,$t3 | t1 = t2 - t3 |
| addi | I型 | add $t1,$t2,100 | t1 = t2 + 100 |
| and | R型 | and $t1,$t2,$t3 | t1 = t2 & t3 |
| or | R型 | or $t1,$t2,$t3 | t1 = t2 | t3 |
| sll | R型 | sll $t1,$t2,4 | t1 = t2 < 4 |
| srl | R型 | srl $t1,$t2,4 | t1 = t2 > 4 |
| lw | I型 | lw $t1,32($t2) | load word,将$t2+32的地址的32位数据存到t1 |
| sw | I型 | sw $t1,32($t2) | store word, 将t1寄存器的内容存到地址$t2+32 |
| lb | I型 | lb $t1,32($t2) | load byte,将$t2 +32地址的 一个字节的内容存到t1寄存器 |
| sb | I型 | sb $t1,32($t2) | store byte,将t1寄存器的内容存到$t2+32地址 |
| beq | I型 | beq $t1,$t2,Label | t1 == t2 则跳转到Label |
| bne | I型 | bne $t1,$t2,Label | t1 不等于 t2 则跳转到Label |
| slt | R型 | slt $t1,$t2,$t3 | t1 = t2<t3 ? 1 : 0 |
| j | J型 | j Label | 无条件跳转到Label |
| jal | J型 | jal Procedure | j and link,跳转,并将返回地址写进Label里 |
| jr | R型 | jr $ra | 跳转到$ra保存的地址 |
栈帧
| 程序和数据的MIPS内存分配 |
|---|
| $sp 栈 动态数据段 |
| 静态数据段 |
| 代码段 |
| 保留 |
栈由内存高端向下生长
32个寄存器的作用
| 名称 | 寄存器号 | 用途 | 调用时是否保存 |
|---|---|---|---|
| $zero | 0 | 常数0 | |
| $v0-v1 | 2-3 | 计算结果和表达式求值 | 否 |
| $a0~$a3 | 4-7 | 参数 | 否 |
| $t0~$t7 | 8-15 | 临时变量 | 否 |
| $s0~$s7 | 16-23 | 保存的寄存器 | 是 |
| $t8~$t9 | 24-25 | 更多的临时变量 | 否 |
| $gp | 28 | 全局指针 | 是 |
| $sp | 29 | 栈指针 | 是 |
| $fp | 30 | 帧指针 | 是 |
| $ra | 31 | 返回地址 | 是 |
| 1号寄存器被汇编器保留,26-27号寄存器被操作系统所保留 |
函数调用时$sp减去一定数值为保存寄存器分配空间,并将$ra、$s0~$s7、$a0~$a3寄存器的内容保存起来,并在函数执行完毕后将开始保存的寄存器的值赋值回去。对于函数递归调用问题,自身递归就是在执行恢复寄存器的操作之前,给参数$a寄存器赋新值并跳转到函数起始处重新执行,由于不断执行函数开头的$sp自减分配栈地址的操作,每一次调用时寄存器的值和返回地址都被保存并在递归完成后进行恢复操作。
addi $sp,$sp,-12
sw $ra,8($sp)
sw $s0,4($sp)
sw $a0,0($sp)
lw $a0,0($sp)
lw $s0,4($sp)
lw $ra,8($sp)
addi $sp,$sp,12
jr $ra3.计算机的算术运算
机器并不能区分数据是有符号数还是无符号数,这是由编译器得出的指令所决定的,如addu和add。 有符号数: 高位1为
无符号数:
加法和减法
溢出检测