——基于MIPS架构
课后整理笔记是一个复习的过程。上学期写了一个数字电路的笔记,感觉这门课一下子得心应手起来。这学期继续这个做法,选几门觉得难的课程整理下笔记
感谢你阅读本笔记,本文不允许任何形式的转载。有任何问题可以与我联系,我的邮箱是[email protected]
计算机系统由软件和硬件组成,这门课主要研究硬件
计算机硬件包括CPU、存储器、I/O设备等
CPU由ALU、控制器、寄存器组成
ALU是运算单元
控制器负责控制信号
CPU位数 = CPU中寄存器的位数 = CPU能够一次并行处理的数据宽度 = 数据总线宽度
例如64位计算机,其CPU中寄存器的位数为64。它一次能并行处理64位的数据。它的数据总线宽度为64
存储器就是内存,由存储矩阵构成,最小存储单位为Byte,即8个bit
总线是指计算机组件间规范化的交换数据的方式
总线分为数据总线、控制总线、地址总线
数据总线是用来传输数据的,是双向的
控制总线是控制数据传输方向的信号线,是双向的
地址总线是传输数据位置的,是单向的
指令:计算机能识别并执行的基本操作命令
指令由操作数和操作码组成。操作码决定要完成什么操作,操作数指参加运算的数据及其所在的地址
指令以二进制的形式存在内存中
指令集:计算机全部指令的集合
程序:完成既定任务的指令序列
1.读取指令
2.指令译码
3.获取数据
4.执行运算
5.存储结果
计算机由控制器、运算器、存储器、输入设备、输出设备五大部分组成
程序和数据以二进制不加区分存在存储器(数据类型是由程序决定的)
计算机只有一个CPU,一个存储器,一套总线。CPU的速度越来越快,但是由于只有一个存储器和一套总线,使得读数据、读指令、存放结果不能并行
为了解决以上问题,提出哈佛结构。提供两个存储器分别存放指令和数据,同时提供两套总线
代价是增加了复杂度
提供两个存储器,但只有一套总线
现在最常见的是混合结构
计算机是数字电路,存储的信息都是二进制信息
这部分网络资料很多,就不记了
原码、反码、补码参考:https://www.jianshu.com/p/36ec7a047f29
这里提一下模的概念,模是符号位的进位位的权值。例如有8位二进制,模是第9位的权值,即28=256
负数的补码为模减去该数的绝对值,这是负数补码的定义,可以越过原码和反码
事实上,有些负数的原码和反码不存在,不能通过反码+1的方法计算补码。比如计算-128的8位补码,-128的8位反码不存在,那么-128的补码为:256-128=128,即1000 0000
机器码的概念:机器码包括原码、反码、补码和移码
不需要保存小数点的位置,所有位置都用来存储数字
包括定点整数、定点纯小数、定点带小数
遵循IEEE 754编码,分为单精度和双精度
浮点数从高位到低位分别是符号域、指数域和尾数域。其中符号域为了正负数的统一,需要加上偏移量
单精度有32位,双精度有64位
参考:https://blog.csdn.net/u010460406/article/details/47027419
直接算
溢出:当最高为向更高位有进位(或借位)时产生溢出
产生的进位或借位由状态寄存器的CF
位保存
加减统一为补码运算
溢出:最高位进位状态⊕次高位进位状态=1,则溢出。溢出只可能发生在同符号的数运算之间
最高位和次高位,一个有进位一个没有进位,则他们的状态异或得1,则结果就有溢出
1.检测0操作数,如果有一个是0就不用算了
2.指数对齐。小的指数向大的对齐。原因是:小的向大的对齐时,指数小的那个数的小数点左移,其尾数域右端的数字被移出,误差小;而反过来误差较大
3.尾数求和。都用补码运算
4.结果规范化
例题:计算1.5 - 27.5(单精度)
首先把两个浮点数表示出来
把1.5的小数点左移,与-27.5的补码相加。得到的结果依然是补码,再变回原码
已经是规范化的小数了,本题结束
当数据存在连续的存储空间时,其地址是就是存储空间的首地址
大字节序:高位存入低地址,低位存入高地址(MIPS采用大字节序)
小字节序:高位存入高地址,低位存入低地址
高级语言:独立于硬件,描述算法
汇编语言:使用助记符号和地址符号来表示指令的语言,又称符号语言
机器语言:依赖硬件,是二进制代码,计算机可以直接执行
汇编:把汇编语言翻译成机器语言的过程
汇编程序:实现汇编过程的软件
汇编语言程序:用户用汇编语言编写的程序
可以看出CISC的指令种类较多,长度不固定
而RISC只有三类指令,长度固定。注意:RISC只有装载和存储可以访问存储器,其他指令都在寄存器之间进行
二者各用用处,这门课我们学习的MIPS架构采用精简指令集(RISC)
MIPS汇编指令基本结构如下图
在下面这条示例指令中,add
是操作码,决定这条指令进行加法操作;a, b, c
是三个操作数,是操作的对象,其中a
是目的操作数b, c
是源操作数
add a, b, c
操作数只有三种,分别是寄存器、存储器和立即数
寄存器操作数:是CPU内部的寄存器,表示方法是美元符加上寄存器的名称或编号,如$s0
,$s7
,$3
存储器操作数:是内部存储器,在MIPS架构下仅用于装载(Load)和存储(Store)指令。表示方法是常数加上括号寄存器的形式,其中的常数是偏移量,如4($s3)
立即数操作数:就是常数,如4
,8
指令中的u
表示操作数据是无符号数。这就解释了为什么之前说内存中的数据类型是程序决定的
指令中的i
表示这条指令的操作数含有立即数
数据传送指令中的w
h
b
分别表示这条指令针对的数据是字、半字、字节
这里将MIPS指令按照功能分类,之后我们还会按照编码方式分类
MIPS有32个通用寄存器($0-$31),具体内容如下图
没列出的$26
,$27
寄存器保留给异常处理函数使用
MIPS数据存储要求边界对齐。半字存储地址需要为偶数;字的存储地址需要为4的整数倍。MIPS指令是32位的,即一个字,所以指令的地址也是4的整数倍
表示方法仅有一种,是常数加上括号寄存器的形式,其中的常数是偏移量,如4($s3)
例如,A
中存储int
,A
保存在$s8
中,请表示A[8]
答案为:32($8)
。因为每一个int
占据4个字节,偏移量为32
是指出现在指令中的常数,如下列指令中的40
addi $s1,$s2,40
立即数可以有10进制或者16进制表达方式。后者需要有0x作为前缀
我们知道MIPS的指令编码都是定长的,那么如何用二进制编码指令,即如何表示指令的操作码和操作数?
回答这个问题前,我们将指令分为R型,I型,J型三种指令。实际上,我们分类的标准是这三种指令有不同的编码形式
三种指令的编码形式如下图
指令格式如下
lx $Rt, Imm($Rs)
显然,装载指令是I型指令。指令中的lx
,Rt
,Rs
,Imm
分别与I型指令的各个域对应
lx
并不代表真的有lx
这个指令,在实际代码中,要被替换成lw
,lh
,lhu
,lb
,lbu
等
lw
指令将一个字的数据拷贝到寄存器。注意MIPS寄存器的左边储存数据的高位,存储器的低地址存放数据的高位
lh
,lhu
拷贝半字到寄存器。由于寄存器是32位,半字只有16位,所以二者需要分别进行有符号扩展和无符号扩展
有符号扩展是在高位补充符号位
无符号扩展是在高位补充0
例如,16位立即数0x8000,进行有符号扩展和无符号扩展得到如下结果
有符号扩展:0xFFFF8000
无符号扩展:0x00008000
lb
,lbu
拷贝字节到寄存器。同样要进行扩展,方式与上述一致
以上都是规则字的装载,下面来讲非规则字的装载。这种情况发生在地址不是4的整数倍的时候
lwl
是左边界对齐非规则字访问。复制存储器中从中间到左边的数据,粘贴在寄存器的左边
lwr
是右边界对齐非规则字访问。复制存储器中从中间到右边的数据,粘贴在寄存器的右边
举个lwl
的例子。lwr
与例子相反,就不举了
从中间的0
到左边界的2
,依次复制到寄存器的左边。结果如下图
非规则字的装载可以和非规则字的存储配合使用,实现小字节序
指令格式如下
sx $Rt, Imm($Rs)
存储指令和装载指令一样,都是I型指令
sx
在实际代码中为sw
,sh
,sb
sw
直接将寄存器中的一个字存到存储器,注意地址必须是4的整数倍
sh
存半字,而且是低半字。因为高位是拓展而来的,不会影响数据的值
sb
存字节,而且是低字节
存储指令中也有非规则字存储指令
swl
是将寄存器中从左边界开始的值,以从中间到左边的方式存到存储器
swr
是将寄存器中从右边界开始的值,以从中间到右边的方式存到存储器
swl
与lwl
过程相反,swr
与lwr
过程相反
举个swl
的例子
得到结果如下
一句话概括非规则装载存储:装载是中间装到边界,存储是边界存到中间
四条都是R型指令。$Rd
,$Rs
代表域
代码如下
lui $Rt,Imm
这是I型指令,功能是把16位立即数赋给寄存器的高16位,低16位补0
代码的u
不是无符号数的意思,而是高位(up)的意思
如何给寄存器赋32位值?需要用到后续课程的逻辑运算指令
先来看4条R型加减运算指令
add $Rd,$Rs,$Rt # 有OF作为溢出标志位
addu $Rd,$Rs,$Rt
sub $Rd,$Rs,$Rt # 有OF作为溢出标志位,运算结果是Rs的值-Rt的值
subu $Rd,$Rs,$Rt
还有2条I型加减运算指令
addi $Rt,$Rs,Imm #Imm是16位的,高16位补充符号位
addiu $Rt,$Rs,Imm #Imm是16位的,高16位充0
立即数参与的时候就没有减法了,因为只要加上一个负数就可以实现减法
mult $Rs,$Rt
multu $Rs,$Rt
乘法结果的符号由参与运算的数的符号决定,所以要区分有符号和无符号(乘法的实现比较复杂,这只是简单理解,想了解更多请看乘法电路)
乘法的结果保存在特殊寄存器中。高32位存在hi
寄存器,低32位保存在lo
寄存器中
想得到结果需要用到前文的mfhi
,mflo
等
与乘法类似
div $Rs,$Rt
divu $Rs,$Rt
进行$Rs/$Rt
的运算,结果保存在特殊寄存器中。余数存在hi
寄存器,商存在lo
寄存器中
先讲与、或、或非、异或四类运算,这里都是位逻辑运算
逻辑运算的具体功能请参考《数字电路》课程
可以通过或非0
,异或1
,实现非运算
and $Rd,$Rs,$Rt #Rs和Rt位与,结果存到Rd
andi $Rd,$Rs,Imm #Imm是16位的,高16位充0后再和Rs位与
or $Rd,$Rs,$Rt #或运算
ori $Rd,$Rs,Imm #Imm是16位的,高16位充0
xor $Rd,$Rs,$Rt #异或运算
xori $Rd,$Rs,Imm #Imm是16位的,高16位充0
nor $Rd,$Rs,$Rt #或非运算,注意没有nori指令
还有一类移位指令,分为逻辑移位和算术移位
# 逻辑移位指令,移入0,都是R型指令
sll $Rd,$Rt,Imm #逻辑左移Imm
srl $Rd,$Rt,Imm #逻辑右移Imm
Sllv $Rd,$Rs,$Rt #逻辑左移,移动的位数是$Rt的值
srlv $Rd,$Rs,$Rt #逻辑右移,移动的位数是$Rt的值
# 算术移位指令,移入符号位,都是R型指令
# 没有算术左移,因为左移会丢失符号位
sra $Rd,$Rt,Imm #算术右移Imm
srav $Rd,$Rs,$Rt #算术右移,移动的次数是$Rt的值
在学这部分知识前,我们先要复习以下几个知识:
1.MIPS指令都是32位的,即4个字节,即1个字
2.MIPS架构的存储器要求边界对齐,字的存放的首地址必须是4的整数倍,也就是地址的最低两位是0
3.指令存放在存储器中,且是顺序存储。在程序中相邻的指令在内存中也相邻
4.PC寄存器指向下一条指令的地址
5.在无跳转指令时,程序依靠PC寄存器依次+4来顺序执行指令;实现跳转的关键是改变PC寄存器的值
有beq
和bne
两条指令,都是I型指令
beq $Rs,$Rt,label # $Rs,$Rt相等时跳转到label
bne $Rs,$Rt,label # $Rs,$Rt不相等时跳转到label
label
是程序前的标号,代表指令的地址。实际上是一个常数,存在Imm域
label
实际上保存的是相对地址,即label-PC
再右移两位的低16位。结果是一个符号数,正数往后跳,负数往前跳
原因是地址的最低两位是0
,没必要存。剩下的从低到高存16位。可见这两条指令的跳转有范围限制
只有一条j
指令
j label # 无条件跳转到label
J型指令的Imm域是26位的。实际上,保存的是label的去除高4位和低2位的中间26位
j
指令的跳转也是有限的,跳转到的指令的地址高4位必须和PC一样
满足条件时,跳转到label
满足条件时,会给第一个寄存器操作数置1
再结合beq
和bne
指令,实现跳转
子程序调用的过程实际上是main
函数向sub
函数跳转的过程
调用子程序时,采用jal
指令,这是一条J型指令
格式如下,label
为标号
jal label
使用jal
指令时,会将PC
寄存器中的值暂存到$ra
寄存器
函数调用结束后,使用jr
指令就可跳转回主程序,这是R型指令,格式如下
jr $ra
调用子程序时,依次使用$a0-$a3
寄存器保存入口参数。使用$v0-$v1
寄存器保存返回值
寻址是指处理器获得数据和指令的存储地址
1.寄存器寻址。例如指令
add $Rd,$Rs,$Rt
,操作数在寄存器中
2.基址寻址。例如指令lw $Rt,(Imm)$Rs
,地址由基地址和偏移地址组成
3.立即寻址。例如指令addi $Rt,$Rs,Imm
,操作数来自指令中的立即数
1.寄存器间接寻址。例如指令
jr $Rs
,PC来自寄存器
2.PC相对寻址。例如指令beq $Rs,$Rt,label
,新PC的值和原PC的值相关
3.伪直接寻址。例如指令j label
,新PC的值基本来自指令
鸽了。
时间局部性:刚刚访问的存储区域又马上访问
空间局部性:访问刚刚访问的存储区域的相邻区域
存储器的发展基本跟不上CPU的脚步。速度快的存储器价格太贵,便宜的存储器速度太慢
计算机内采用分级的存储结构提高效率,如下图
如果将经常使用的数据或指令装载到高速缓存中,就可以提高速度
cache的容量小于内存,不可能把所有的数据都装进cache。故需要建立一种映射机制,也就是说cache数据和内存数据的对应关系
这里有三种映射机制,分别是直接映射、全相联映射、组相联映射
参考:https://blog.csdn.net/l_nan/article/details/78883996
将外存当作内存使用
管理方式有分段管理和分页管理
鸽了。
把内存和外存分为大小相同的页,以页为单位装载
页表存储在内存中,页表的索引是虚拟地址,数据是物理地址
可以建立多级页表,索引是虚拟地址的一部分,数据是下一级页表的地址
把页表存进高速缓存(全相联映射),提高查找的效率