2.指令集系统结构
第二章:指令集系统结构
存储单元和寻址方式:
计算机按照''字'来组织存储单元,这是由处理器能够处理的基本数据单位的大小决定的,例如32位计算机的数据总线的位数为32位,它一次就能传输32位的数据,因此它的字长也是32,同理64位计算机的字长为64。 除了数据总线外计算机还有地址总线,它是用来寻找内存单元的位置的,但是为每一位内存分配地址太过浪费,而按字分配不同的处理器字长并不同一,所以一般按照八位(1字节)分配地址,这就按字节寻址,而地址总线上的数据表示的地址就是字节的编号,32位处理器最大的寻址空间就是4GB,这是由地址总线的位数决定的。 在32位处理器中一个字中包含四个字节而大端小端则指的是字节在字中的两种排列方式。字中最左边存放数据的最高有效位,右边为最低有效位,按照大端的排列方式低地址的字节存放数据的高有效位,而高地址的字节存放地有效位,小端排列方式则正好相反,如下图所示。
字的对齐就是指一个字的开始位置是字中所包含的字节数的整数倍,字对齐能够方便处理器访问存储单元,加速数据的读取速度。
常见处理器寄存器:
处理器在工作中,通过自身的寄存器与存储器中的数据和指令交互,进行数据处理。不同的寄存器有着不同的作用,下面是一些重要寄存器的介绍。
- 通用寄存器:
- 存储数据和中间结果,可用于算术和逻辑操作。通常有多个通用寄存器,如
R0
到R31
(在某些架构中可能更多或更少)。
- 存储数据和中间结果,可用于算术和逻辑操作。通常有多个通用寄存器,如
- 程序计数器(PC,Program Counter):
- 指向下一条将要执行的指令的地址。执行指令后,PC会自动更新。
- 指令寄存器(IR,Instruction Register):
- 存储当前正在执行的指令。
- 堆栈指针(SP,Stack Pointer):
- 指向当前堆栈的位置,堆栈用于存储临时数据,比如函数调用的返回地址和局部变量。
- 基址寄存器和索引寄存器:
- 用于内存寻址。在某些指令集中,这些寄存器帮助计算内存地址。
- 状态寄存器(或程序状态字寄存器,PSW):
- 包含处理器的当前状态,包括条件码(如零标志、进位标志等),指示运算的结果状态。
- 链接寄存器(LR,Link Register):
- 当发生函数调用,中断时存放当前程序执行的位置,即保存PC寄存器的值。
RISC和CISC:
处理器执行命令是通过一条条二进制指令进行的,处理器所使用的所有指令称为指令集,然而不同架构的处理器的使用的指令集也不同。X86架构的处理器使用复杂指令集,搭载这种处理器的计算机称为复杂指令集计算机(CISC),ARM架构的处理器使用精简指令集,搭载这种处理器的计算机称为精简指令集计算机(RISC)。下面是两种指令集的的特点
- RISC:
- 每条指令为一个字长,指令简单运行效率高。
- 使用load/store体系结构,只能通过Load和Store命令操作存储器操作数(存储在主存中的数据),算数或者逻辑运算中的所有操作数必须是寄存器操作数(存储在处理器寄存器中的数据)或者是明确指出的数据。
- CISC:
- 每条指令的长度不固定,但是可以实现复杂的操作。
- 寻址方式复杂多变,能够有效地操作复杂数据结构。
RISC精简了硬件设计,使处理器高效运行,但是同时为实现目的需要调用更多的指令,造成软件程序更为庞大;CISC仅需较少的指令就能实现目标功能,但是由于指令集的复杂它的一个指令往往需要处理器执行更多的步骤才能完成。因此两种指令集各有优缺点(要么软件换硬件,要么硬件换软件)
常见汇编命令:
介绍一下精简指令集的常见汇编指令:
ADD R4,R2,R3 #将R2和R3寄存器中的值相加存储在R4中
ADD R4,R2,#400 #将R2中的值加上400存放在R4中,#400称为立即执行数
ADDI R4,R2,400 #和上式效果相同
Load R2,A #将存储单元A中的内容存放在R2中
Store R4,B #将R4寄存器中的内容存放在内存单元B中
Call C #调用C位置的子程序
子程序调用与堆栈:
二进制程序由一条条处理器指令组成,处理器在执行程序时按照顺序一条条的执行指令,PC寄存器中存放着下一条指令存放的地址,当一个模块需要在不同位置多次调用时,通常会把他单独存放在一个位置(就像C语言中的函数一样)称这样的模块为子程序,当需要使用子程序时就让PC寄存器保存下当前的值,然后跳转到子程序的位置。当子程序执行完毕,就会根据PC寄存器之前保存的值跳转回到程序原来的位置继续执行下面的指令。 上面这个过程还存在需要讨论的细节,就是PC的值保存在什么地方。在发生一次子程序调用时,PC寄存器的值可以保存在LD寄存器中,当子程序执行完之后调转到LD寄存器的位置继续执行即可。但是如果发生镶嵌调用,如果还用这样的方法第一次调用的返回值就会被覆盖。 因此需要采用栈存储的方式,当子程序发生调用时将它的返回地址和调用参数存放在栈中,当调用结束后将存放的数据出栈就即可,由于栈后进先出的特点可以在将镶嵌调用的地址和参数据存放在栈中,它会按照顺序依次返回。 在程序执行的过程中栈中存放的就是程序的局部变量,子程序的参数,返回值和保存的返回地址。为了操作栈空间我们需要一个SP寄存器专门用于存放指向栈顶位置的指针,还有FP寄存器(结构体指针,这一般由一个通用寄存器存储)访问子程序的参数和局部变量。SP始终指向栈顶,FP指针指向的位置向下偏移为子程序参数,向上偏移一次保存着局部变量和寄存器的保存值。