第一节:指令系统

指令集

一台计算机只能运行自己的指令集,因为指令集和硬件有关

ISA是软件所能见的部分,软件可以调用计算机内的指令,例如操作系统实现一些功能

指令格式

指令字长而言,其可定长的,也可不定长,定长与否只影响执行操作复杂度

如果不定长指令,一般都采取填充的方式,否则可能导致存取一条指令需多次访存

流水线需要保证每条指令的取指令时长均一致,定长指令更适合于流水线作业

指令种类中需要注意的就是各个指令的访存次数,需要看清,及目的和源操作数的位置

零地址指令可以用于数据结构的后缀表达式、前缀表达式的求和以及计算

四地址指令的A4字段是直接给出的地址,不需要单独访存

操作码及其拓展

做题的时候一般需要区分清楚是定长操作码还是非定长操作码

定长操作码和非定长操作码均是对“操作码”这个概念阐述的,和指令定长与否无关

拓展操作码设计方式从高位开始设计,而不是从低位向上设计,这点需要注意

同时必须保留拓展位,因为不能产生后者码和前者码前缀相同的情况

如果一定要拓展那么就是和哈夫曼树联系,变长编码,根据访问的频率划分哈夫曼编码

指令类型

重点强调转换指令,JMP/CALL/RET/TRAP(有争议,一般认为是特殊的无条件转移指令)

上述均是常见的无条件转移指令,需要刻意留意这一些细节,CALL一定会RET

而JMP不一定会RET,TRAP具体看情况,后面中断一节有具体阐述,还有一些联系

关注TRAP指令,建议联系中断一节具体阐述


习题总结分析:

1、2:自命题题目,统考不会这样出

关注下之前统考考过的一个类型,就是ISA的主要规定内容,其也是联系实际考察的

3:下一条指令的地址由PC给出,每次完成对PC内取指令后PC均会自增该指令地址长度

关于自增,其实分为多种情况,主要和指令长、存储字长相关

PC在取指令周期内完成自增,在指令执行阶段就是对应下一条指令的地址,自然要加

IR中存放的是当前指令的指令内容,应该是在每次取指令周期内更新

5:程序控制类指令的目的就在于使得程序具有逻辑,可执行循环、判定、嵌套等

6:中断隐指令由硬件实现,P247

9:单地址指令即可能有两个操作数,也可能有一个操作数,一个操作码而言

既可以是对一个数进行操作,也可以是对两个数进行操作的,很多都是单操作数指令

16:可补充,见网页即可

综合2:

当操作码定长的时候,其长度以最短的情况为最长长度,即当满地址时的剩余码长

在做题前就需要区分这是定长操作码还是不定长操作码,否则无法确定“最多”有几条

统考曾经多次考察最多有多少条指令,若是不定长操作码就会有些细节改变


第二节:指令寻址方式

指令寻址

PC指令地址会在取指令周期完成一次自增,其自增长度即为该条指令的长度

自然其后续周期内均指向下一条指令的初始地址

同时需要留意的就是,当指令采用边界对齐的情况下,PC下次就指向下一个边界源

相对跳转指令执行周期内,PC已然完成自增,因而需要考虑自增的量,再计算偏移地址

不过如果是绝对地址,那么就没有什么好说的,直接覆写PC内的内容

数据寻址:

关键在于分清形式地址和实际地址,以及最终的数据,三者之间的区别

尤其也需要注意题目中问的是实际地址还是最终取得的数据

在复合寻址内,以上一次取得的有效地址为下一层复合的基本形式地址,而非内容

易错的点就是混淆形式地址和有效地址以及有效地址内的内容,以及间接寻址

对于访存类型的地址,其地址必然是一个正数(统考多次考察),转移类则是正负补码

偏移寻址往往是能够覆盖整个主存空间的,如果能够覆盖那么转移空间即是整个主存

具体类型补充:

重定向寄存器、页表基址寄存器、段表基址寄存器即为基地址寄存器

堆栈类型的寻址需要留意栈顶、栈底各自的位置、自增的方式

硬堆栈完全采用寄存器,不需访主存

软堆栈是需要访问一次主存的,因为软堆栈本身就是从主存中划分一块出来用的

堆栈寄存器一般是专用的,其隶属于通用寄存器组


习题总结分析:

1:定长指令提供了拓展操作码的可能,非定长指令的操作码既可定长也可非定长

但就拓展操作码而言,其最适用是定长指令(因为是基于指令长度有限才提出的策略

指令不定长会增加译码难度,操作码不定长也会增加硬件电路复杂度

2:不论是何种转移指令,其最终均是输入到PC内进行更改才能完成转移的

TRAP类型指令也同样需要修改PC,因而可以说转移类指令均是修改PC来实现功能的

3:指令中的形式地址一般比较短,能够寻址的范围比较小

整个计算机中的寄存器比较少,所以如果采用寄存器寻址方式,其形式地址就很短

寄存器的寻址范围非常大,主存的地址很长,但主存内容寻址范围非常大

7:复合寻址,先变址后间址,变址得到的结果再去进行一次间址,访问主存得到地址

变址得到的是其上一层的有效地址,被作为本层的形式地址进行复合访问

17:考察补码的表示范围,移码和补码表示宽度一样,但表示的具体范围不同

14、16、21、24:均是对PC自增的考察,取指令后PC就会进行一次自增

当最终执行的时候就需要转移到下一条指令的位置(边界对齐下

对于21:

低字节作为字地址的存放方式,本质含义就是数据的低位放在存储位置的开始

简单来说就是小端存储,这种考试里面碰到了不要取死磕意图,直接猜含义就做就行

20:题目问的是有效地址而非操作数,特别容易混淆的地方

其问的是最终的有效地址是什么,而不是问的最终的操作数是什么,这个是题干

22:特别需要注意这个“补码表示”,当偏移量为负数的情况下尤其需要注意这一点

当符号位为负的情况下,就需要首先向高位拓展符号位,然后再进行相加

对于这类二进制相加,直接考虑用加法器中的方法判断是否溢出、进位等事件

26:关于这边的相加,重新进行一次回顾和总结:

ZF:全零则出一

OF:最高位的进位异或次高位的进位

CF:最高位的进位和输入位异或的结果,一般用于无符号整数的运算

加法则输入为零,减法则输入为一,对于无符号整数的运算而言,其符号位是隐含的

因而只会对运算器内的减数进行取反加一,如果不产生进位即为溢出(相加为负数

当加法的情况下,输入为零,若两个正数相加,最终超出表达范围,自然产生进位溢出

具体到题目内,默认A-B方式,即A-B>0,那么就可以进行分析

当A-B>0的情况下,即减法,最高位产生进位仍是正数,那么CF必然就是0(异或逻辑

且总体不可能为零,那么就是ZF=0,自然就能选出C这个结果

需要注意的几个点:

在计算机运算中不论加减法均是补码运算

有符号数还是无符号数,都是经过一样的电路运算的,因而标志位都会生成

同理,有符号数和无符号数均可直接运算,判断溢出依靠电路逻辑

CF、OF的异或逻辑,容易被混淆,这一点需要注意

28:注意偏移量取值范围和指令地址取值范围,一者跳转后偏移结果,和PC自增有关!

后面的综合题就出了这样一道题

29:典型的出题方式,有效地址是XXX,还有一种可能的坑法就是操作数是XXX

两者就会有巨大的差别,详细可以参考之前的20题

33:主存的地址不支持负数

只有偏移量是支持补码表示为负数的情况,地址本身均是不支持负数或者溢出情况的

寄存器的地址同样不允许负号的产生,只能是正数,尤其需要重视寻址范围

此外,形式地址需要按具体情况决定直接用二进制表示还是采用的补码方式表示

偏移法都采用补码

综合3:

注意主存按“字”编址,自然就会使得指令自增长度变为一,这种细节特别需要考虑

一个是指令字长,另外一个就是编址方式,两者决定了这次PC的增额


第三节:程序机器代码表示

寄存器

建议按照名称类别记忆,是需要完整背诵的,具体功能不再赘述,除EBP和ESP外均通用

汇编指令

双操作数指令不能均来自内存、三操作数指令第一个必须是寄存器

目的操作数不能是常量

控制流指令中谈到的IP实际上就是对应的PC

转移指令

个人认为刻意需要留意原先C语言中的表达式和汇编语言中指令的表达式间的区别

这可能就会影响指令阅读中下一条指令到底是IF逻辑还是ELSE逻辑,从而导致混淆出现

此外,某一些跳转指令的执行也会改变指令逻辑,需要和刻意和原程序对比理清楚的

CMP中的条件就是第一个关注对象,后续指令执行的顺序和原程序顺序就是第二比较点

CALL/RET,后续展开的重点内容,需要单独掌握(统考往往结合C语言程序考察

选择、循环语句机器指令

对于不同的循环、选择结构,其跳转指令的条数不一定相同

即使是相同功能的循环、选择,其语句顺序、语句数量也不一定是相同的

重点关注选择语句的CMP中具体的比较方式,是和原逻辑相符还是相反

这会直接影响后续的指令执行流程,影响何处执行的是IF逻辑,何处执行的是ELSE逻辑

循环、选择结构体内至少包含一条条件转移指令,不一定包含无条件转移指令

当选择结构没有ELES,那么其就可以不包含无条件转移指令

过程调用(重点)

调用CALL语句,将当前IC值压栈,ESP自增

再无条件跳转到新程序的第一句语句,至此CALL指令执行结束

但每个子程序开头都需要例行公事

首先将主程序的基地址压栈,ESP自增

这里就已经可以看出一个子程序的基地址中必然是其父程序的基地址(Main函数外

然后将ESP赋值给EBP,使得EBP指向当前基地址,后续就是正常使用这个帧栈

再考虑返回操作,即子程序中的RET

在RET前需要例行公事

首先将EBP赋值给ESP,使得其指向子程序基地址(清空当前函数帧栈

然后进行一次出栈操作,并将出栈的基地址赋值给基地址寄存器,恢复父程序基地址

执行RET指令,出栈上一层的IC,恢复IC寄存器的值,并无条件跳转回该指令地址

过程调用补充

对于过程调用而言,分单层和多重嵌套调用

如果是嵌套循环那么必须是压栈,如果只有一层那么可以依靠寄存器暂存保护量

CALL和RET均是无条件转移指令,LOOP循环指令默认是对ECX寄存器操作的

函数的帧栈在内存中是反地址自增的,也就是反向存放的,高地址向低地址延申生长

所以EBP、ESP的自增、自减和栈的增长方向是相反的,需要留意

其余便是EBP、ESP自增、自减和出入栈的操作方式限制,详细可以参考数据结构

先减再入、先出再加;先入再减、先加再出;需要注意的无非就是操作顺序

访问帧栈可采用Move/Push/Pop/Sub/Add等方式操纵栈指针和数据,要求能看懂

帧栈大小是16B的整数倍,一定是边界对齐的,可能会产生一定的内部碎片

调用者、被调用者各自有需要保护的寄存器存在,当然不必要的话不保护覆盖也可

下列是帧栈的内容,因为过程调用本身和中断等联系密切,所以建议重点掌握

PSW其内部标志位重点考察的是CF、OF、ZF、SF,其他还有IF(中断)、TF(陷入)


习题总结分析:

1、2:对于这类题目,规范按照电路逻辑即可,即加法直接补码相加看各自进位号

减法则减数全部取反加一,然后再进行加法观察其各自进位结果进行异或,得到标志

只需要关心电路进位,而根本不需要关心到底是无符号数还是有符号数溢出与否

6:PC在取指令后即完成自增,在执行阶段必须加上自增长度

9:该语句包含IF和ELSE两个选择逻辑,需要条件跳转和无条件跳转两个转移指令存在

至于两段逻辑块的先后顺序是没有要求的,只需要改变CMP条件即可改变顺序

10:循环结构、选择结构均至少包含一段条件转移指令,选择结构若有ELSE还要无条件

11:CALL指令的转移目标一定会在指令中给出,C选项即为可用寄存器保存非嵌套


第四节:RISC与CISC

大部分内容应以书为主,建议全文背诵,这里仅作小幅度补充说明

CISC是第五章的主要内容,也就是计组中研究的基本都是基于微程序控制器的指令

如果非Load/Store指令能够访存,那么必然是CISC指令,RISC必须用流水线

流水线的基本要求是指令长度尽可能一致、边界对齐、指令格式规整、大部分不可访存