【计算机组成原理】指令系统

一、指令系统

1.1 指令的基本格式

1.1.1 指令的定义

       指令(又称机器指令):是指示计算机执行某种操作的命令,是计算机运行的最小功能单位。一台计算机的所有指令的集合构成了该机的指令系统,也称为指令集

注意:一台计算机只能执行自己指令系统中的指令,不能执行其他系统的指令。

1.1.2 指令的格式

       一条指令就是机器语言的一个语句,他是一组有意义的二进制代码,一条指令通常要包括操作码字段和地址码字段两个部分:

       一条指令可能包含0个,1个,2个地址码,根据地址码的不同,可以将指令分为零地址指令,一地址指令,二地址指令……

1.1.3 按地址个数分类

1.1.3.1 零地址指令

       不需要操作数,如:空操作、停机。关中断等操作

       堆栈计算,两个操作数隐含存放在栈顶和次栈顶,计算结果栈顶压回。

1.1.3.2 一地址指令

       只需要单操作数,如加1,减1,取反,求补等,指令含义:OP(A1) -> A1,完成一条指令需要3次访存:取指 -> 读A1 -> 写A1

       需要两个操作数,但其中一个操作数隐含在某个寄存器中,指令含义:(ACC)OP(A1) -> ACC,完成条指令需要2次访存:取指 -> 读A1

1.1.3.3 二地址指令

       常用于需要两个操作数的算术运算、逻辑运算相关指令,指令含义:(A1)OP(A2) -> A1,完成一条指令需要访存4次:取指 -> 读A1 -> 读A2 -> 写A1

1.1.3.4 三地址指令

       常用于需要两个操作数的算术运算、逻辑运算相关指令,指令含义:(A1)OP(A2) -> A3,完成一条指令需要访存4次:取指 -> 读A1 -> 读A2 -> 写A3

1.1.3.5 四地址指令

       指令含义:(A1)OP(A2) ->A3,A4 = 下一条将要执行指令的地址,完成一条指令需要访存4次:取指 -> 读A1 -> 读A2 -> 写A3

        正常情况下:取指令之后,PC + 1,指向下一条指令,而四地址指令:执行指令后,将PC的值修改为A4所指的地址。

1.1.4 按指令长度分类

指令字长:一条指令的总长度(可能会变)

机器字长:CPU进行一次整数运算所能处理的二进制数据的位数(通常与ALU直接相关)

存储字长:一个存储单元中的二进制代码位数(通常与MDR位数相同)

半字长指令、单字长指令、双字长指令——指令长度是机器字长的多少倍

       指令字长会影响指令所需时间。如:机器字长 = 存储字长 = 16bit,则取一条双字长指令需要两次访存。

  • 定长指令字结构:指令系统中所有指令的长度都相等
  • 变长指令字结构:指令系统中各种指令的长度不等

1.1.5 按操作码的长度分类

  • 定长操作码:指令系统中所有指令的操作码长度都相同,控制器的译码电路设计简单,但灵活性较低
  • 变长操作码:指令系统中各个指令的操作码长度可变,控制器的译码电路设计复杂,但灵活性较高

1.1.6 按操作类型分类

  • 数据传送:
  • 算术逻辑操作:
  • 移位操作:
  • 转移操作:
  • 输入输出操作:

1.2 扩展操作码指令格式

扩展操作码指令格式 = 定长指令字结构 + 可变长操作码

在设计扩展操作码指令格式时,必须注意一下两点:

  1. 不允许短码是长码的前缀,即短操作码不能与长操作码的前面部分的代码相同
  2. 各指令的操作码一定不能重复

       通常情况下,对使用频率较高的指令,分配较短的操作码;对使用频率较低的指令,分配较长的操作码,从而尽可能减少指令译码和分析的时间。

二、指令的寻址方式

2.1 指令寻址

  • 顺序寻址:(PC) + "1" -> PC(一个指令字长)
  • 跳跃寻址:由转移指令指出,每次转移指令,一定要先将PC自动加1,然后跳跃到地址。

2.2 数据寻址

在数据寻址中,我们都先以一地址指令为例来讨论一下10种方式:

2.2.1 基本寻址(7种):

  • 数据寻址:确定本条指令的地址码指明的真实地址。

  • 直接寻址:指令字中的形式地址A就是操作数的知识地址EA,即EA = A,该指令访存两次
    • 优点:简单,指令执行阶段仅访问一次主存,不许专门计算操作数的地址。
    • 缺点:A的位数决定了该指令操作数的寻址范围,操作数的地址不易修改。
  • 间接寻址:指令的地址字段给出的形式地址不是操作数的真正地址,而是操作数有效地址所在的存储单元的地址,也就是操作数地址的地址,即EA = (A)。
    • 优点:可扩大寻址范围(有效地址EA的位数大于形式地址A的位数),便于编值程序(用间接寻址可以方便地完成子程序返回)
    • 缺点:指令在执行阶段要多次访存

  • 寄存器寻址:在指令字中直接给出操作数所在的寄存器编号,即EA = R,其操作数在由R1所指的寄存器内。该指令访存1次。
    • 优点:指令在执行阶段不访问主存,只访问寄存器,指令字短且执行速度快
    • 缺点:寄存器价格昂贵,计算机中寄存器个数有限
  • 寄存器间接寻址:寄存器R1中给出的不是一个操作数,而是操作数所在主存单元的地址,即EA = (R1)。
  • 隐含寻址:不是明显地给出操作数的地址,而是在指令中隐含着操作数的地址。
    • 优点:有利于缩短指令字长
    • 缺点:需要增加存储操作数或隐含地址的硬件

  • 立即寻址:形式地址A就是操作数本身,又称为立即数,一般采用补码形式。#表示立即寻址特征。该指令访存1次。
    • 优点:指令执行阶段不访问主存,指令执行时间最短
    • 缺点:A的位数限制了立即数的范围

2.2.2 偏移寻址(3种):

  • 基址寻址:将CPU中基址寄存器(BR)的内容加上指令格式中的形式地址A,而形成操作数的有效地址,即EA = (BR) + A。有专门的寄存器和通用寄存器(需要指明寄存器所在的位置)
    • 优点:便于程序“浮动”,方便实现多道程序并发运行,可扩大寻址范围

扩展:程序运行前,CPU将BR的值修改为该程序的起始地址(存在操作系统PCB中)

       注意:基址寄存器是面向操作系统的,其内容由操作系统或管理程序确定。在程序执行过程中,基址寄存器的内容不变(作为基地址),可由用户决定哪个寄存器作为基址寄存器,但其内容仍由操作系统确定。 

  • 变址寻址:有效地址EA等于指令字中的形式地址A与变址寄存器IX的内容相加之和,即EA = (IX) + A,其中IX可为变址寄存器(专用),也可用通用寄存器作为变址寄存器。
    • 注意:变址寄存器是面向用户的,在程序执行过程中,变址寄存器的内容可由用户改变,形式地址A不变(作为基地址),其适合编值循环程序。
  1. 基址 && 变址复合寻址:先基址后变址寻址:EA = (IX) + ((BR) + A)
  • 相对寻址:把程序计数器PC的内容加上指令格式中的形式地址A而形成操作数的有效地址,即EA = (PC) + A,其中A是相对于PC所指向的位移量,可正可负,补码表示。
    • 优点:这段代码在程序内浮动时不用更改跳转指令的地址码,因此便于程序的浮动。

硬件是如何实现数的“比较”

  • 通过cmp指令比较a和b,实质上是用a - b
  • 相减的结构信息会记录在程序状态字寄存器中(PSW)
  • 根据PSW的某几个标志位进行条件判断,来决定时候转移

2.2.3 堆栈寻址: 

  • 堆栈寻址:操作数存放在堆栈中,隐含使用堆栈指针(SP)作为操作数地址。

       堆栈是存储器(或专用寄存器组)中一块特定的按“后进先出”原则管理的存储区,该存储区中被读/写单元的地址是用一个特定的寄存器给出的,该寄存器称为堆栈指针。

三、机器级代码

3.1 高级语言与机器级代码之间的对应

机器级代码:机器语言 + 汇编语言

3.1.1 x86汇编语言指令基础

指令的作用:改变程序的执行流;处理数据

指令的格式:操作码 + 地址码

  • 操作码:怎么处理?
  • 地址码:数据在哪里?在寄存器中(在指令中给出“寄存器名”),在主存中(在指令中给出“主存地址"),在指令中(直接在指令中给出要操作的数,也就是”立即寻址“)

       如何指明内存的读写长度:dword ptr ——双字,32bit、word ptr —— 单字,16bit、byte ptr ——字节,8bit。

3.1.2 X86架构的CPU,有哪些寄存器??

3.2 x86常见的汇编指令

3.2.1 常见的算术运算指令

3.2.2 常见的逻辑运算指令

3.2.3 常见的其他指令

  • 用于实现分支结构、循环结构的指令:cmp、test、jmp、jxxx
  • 用于实现函数调用的指令:push、pop、call、ret
  • 用于实现数据转移的指令:mov

3.3 AT&T格式和Intel格式

3.4 选择语句的机器级表示(分支结构)

       无条件转移指令——jmp<地址> 将PC无条件转移到<地址>,<地址> 可以用常数给出,可以来自于寄存器,可以来自于主存,可以用’标号‘锚定。

       条件转移指令——jxxx  通常先利用cmp指令进行比较

 扩展:cmp指令的底层原理

3.5 循环语句的机器级表示

用条件转移指令实现循环,需要4个部分组成:

  1. 循环前的初始化
  2. 是否直接跳过循环
  3. 循环主体
  4. 是否继续循环

用loop指令实现循环

        loop指令等价于:ecx--,cmp ecx,0,  jne looptop

3.6 函数调用——机器级表示

3.6.1 call,ret指令

  • 函数调用指令:call <函数名>
  • 函数返回指令:ret

call指令的作用:

  • 将IP旧值圧栈保存(保存在函数的栈帧顶部)
  • 设置IP新值,无条件转移至被调用函数的第一条指令

ret指令的作用:

  • 从函数的栈帧顶部找到IP旧值,将其出栈并恢复IP寄存器

3.6.2 如何访问栈帧

  • 标记栈帧范围:EBP、ESP寄存器
  • 访问栈帧数据:push、pop指令

3.6.3 如何传递参数和返回值

每一个函数栈帧中包含哪些内容?

栈帧最底部一定是上一层栈帧基址(ebp旧值)

栈帧最顶部一定是返回地址(当前函数的栈帧除外)

局部变量:C语言中越靠前定义的局部变量越靠近栈顶

调用参数:参数列表中越靠前的参数越靠近栈顶

gcc编译器将每一个栈帧大小设置为16B的整数倍(当前函数的栈帧除外)

扩展:

 

3.6.4 总结:

       栈帧:在函数调用栈中,一个栈帧对应一层函数,用于存储每层函数相关的一些信息,栈底在高地址方向,栈顶在低地址方向,以4个字节为单位操作栈帧。

       ebp、esp寄存器:标记了当前正在执行的函数栈帧范围,ebp指向当前函数栈帧底部4字节,esp指向当前函数栈帧顶部4字节

       push、pop指令:push指令将数据压入栈顶,并将esp减4;pop指令将栈顶元素出栈,并将esp加4

       如何切换栈帧?在每个函数的开头,需要例行执行enter指令——等价于push ebp  mov ebp,esp;每个函数ret之前,需要例行执行leave指令——等价于mov esp,ebp   pop  ebp

call指令:1.将IP旧值压栈保存(保存在函数的栈帧顶部);2.设置IP新值,无条件转移至被调用函数的第一条指令

        ret指令:从函数的栈帧顶部找到IP旧值,将其出栈并恢复IP寄存器

        访问当前函数的局部变量——[ebp - 4]   [ebp - 8]

        访问上一层函数传回来的参数——[ebp + 8]  [ebp + 12]

        一个栈帧包含:1.上一层栈帧的基址(ebp旧值)2.若干个局部变量  3.未使用区  4.部分寄存器值  5.若干个调用参数  6.返回地址(IP旧值)

四、CISC和RISC

CISC:设计思路:一条指令完成一个复杂的基本功能

RISC:设计思路:一条指令完成一个基本“动作”,多条指令组合完成一个复杂的基本功能

相关推荐

  1. 华中科技大学-计算机组成原理-mooc-指令系统

    2024-06-16 23:54:03       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-16 23:54:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-16 23:54:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-16 23:54:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-16 23:54:03       20 阅读

热门阅读

  1. SqlSugar 集成

    2024-06-16 23:54:03       8 阅读
  2. 力扣1482.制作m束花所需的最少时间

    2024-06-16 23:54:03       8 阅读
  3. 记录碰到的json转换异常

    2024-06-16 23:54:03       5 阅读
  4. 网络安全sql注入实战演示

    2024-06-16 23:54:03       9 阅读
  5. Python 调用 C 和 C 调用 Python 方法

    2024-06-16 23:54:03       9 阅读
  6. Optional详解和常用API

    2024-06-16 23:54:03       7 阅读
  7. ssh 两次跳转,通过跳板机直接登录设备

    2024-06-16 23:54:03       8 阅读