文章目录
- 4.1 指令格式
-
- 4.1.1 指令的基本格式
-
- 1. 零地址指令
- 2. 一地址指令
- 3. 二地址指令
- 4. 三地址指令
- 5. 四地址指令
- 4.1.2 长操作码指令格式
- 4.1.3 扩展操作码指令格式
- 4.1.4 指令的操作类型
- 4.2 寻址指令
-
- 4.2.1 指令搜索和数据搜索
-
- 1. 指令寻址
- 2. 数据寻址
- 4.2.2 常见的数据搜索方法
-
- 1. 隐含寻址
- 2. 立即(数)寻址
- 3. 直接寻址
- 4. 间接寻址
- 5. 寄存器寻址
- 6. 间接搜索寄存器
- 7. 相对寻址
- 8. 基址寻址
- 9. 变址寻址
- 10. 堆栈寻址
- 4.3 程序的机器级代码表示
-
- 4.3.1 常用的汇编指令介绍
-
- 1. 相关寄存器
- 2. 汇编指令格式
- 3. 常用指令
-
- 1. 数据传输指令
- 2. 算术和逻辑操作指令
- 3. 控制流指令
- 4.3.2 过程调用的机器级表示 TODO
- 4.3.3 选择句子的机器级表示 TODO
- 4.3.4 循环句的机器级表示 TODO
- 4.4 CISC和RISC的基本概念
-
- 4.4.1 CISC
- 4.4.2 RISC
- 4.4.3 CISC和RISC对比
4.1 指令格式
指令(机器指令)是指指计算机执行某种操作的命令,计算机所有指令的集合构成机器,也称。 在硬件和软件的交界面上,指令系统是计算机的主要属性。
4.1.1 指令的基本格式
指令是机器语言的句子,是一组
通常包括指令和 操作码指出指令应执行什么性质的操作以及具有什么功能。 地址码给出操作指令或数据的地址。
。与机器字长无固定关系,包括单字长指令、半字长指令和双字长指令。
在指令系统中,如果所有指令的长度相等,则称为,否则称为。由于主存一般按字节编写,
指令可分为以下格式:
1. 零地址指令
OP |
---|
只有操作码OP,没有显式地址。有两种可能性:
- 不需要操作数的指令。 空操作、停机、关中断
- 用于堆栈计算机,操作数量隐含从堆栈中弹出,结果压入堆栈
2. 一地址指令
OP | A 1 A_1 A1 |
---|
- 根据目的操作数的单操作数指令 A 1 A_1 A1地址读操作数,OP结果存回原地址。也就是说,OP( A 1 A_1 A
1 )-> A 1 A_1 A1 - 隐含约定目的地址的双操作数指令,在 A 1 A_1 A1读取源操作数,目的操作数可以隐含约定由其他地方提供,例如ACC(累加寄存器),运算结果也存入ACC中
3. 二地址指令
OP | A 1 A_1 A1(目的操作数) | A 2 A_2 A2(源操作数) |
---|
指令含义: ( A 1 ) (A_1) (A1)OP( A 2 A_2 A2)-> A 1 A_1 A1 源操作数从 A 2 A_2 A2得到,目的操作数以及结果存入在 A 1 A_1 A1位置
4. 三地址指令
OP | A 1 A_1 A1 | A 2 A_2 A2 | A 3 A_3 A3(结果) |
---|
指令含义: ( A 1 ) O P ( A 2 ) − > A 3 (A_1)OP(A_2)->A_3 (A1)OP(A2)−>A3 若地址字段都是主存地址,则执行一条三地址指令需要访问存储器四次,包括一次取指令,两次取数据和一次存数据
5. 四地址指令
OP | A 1 A_1 A1 | A 2 A_2 A2 | A 3 A_3 A3(结果) | A 4 A_4 A4(下址) |
---|
A 4 A_4 A4为下一条即将执行的指令的地址
4.1.2 定长操作码指令格式
定长操作码指令,一般 n n n位操作码字段的指令系统最多能表示 2 n 2^n 2n条指令。
4.1.3 扩展操作码指令格式
为了,可采取可变长度指令。即全部指令的操作码字段的位数不固定,且分散地存放在指令字的不同位置上。
最常见的变长操作码方法是
扩展操作码指令格式:定长指令字结构+可变长操作码
常见题型
单个地址长度为n,上一层留出m种状态,则下一层可以扩展出m2n种状态
设计扩展操作码指令格式时,需要注意
- 不允许短码是长码的前缀,即
- 各指令的操作码一定不能重复
4.1.4 指令的操作类型
设计指令系统必须考虑提供哪些操作类型
- 数据传送:包括寄存器之间的传送(MOV)、内存单元读取数据到CPU寄存器(LOAD)、CPU寄存器写数据到内存单元(STORE)等
- 算术和逻辑运算:主要有加(ADD)、减(SUB)、比较(CMP)、乘(MUL)、除(DIV)、加一(INC)、减一(DEC)、与(AND)、或(OR)、取反(NOT)、异或(XOR)
- 移位操作:算数移位、逻辑移位、循环移位
- 转移指令:无条件转移指令(JMP)、条件转移指令(BRANCH)、调用(CALL)、返回(RET)、陷阱(TRAP)等
- 输入输出操作:完成CPU与外部设备交换数据或传送控制命令及状态信息
4.2 指令的寻址方式
寻址方式是指的方式,即的方法。 寻址方式分为指令寻址和数据寻址两大类。
4.2.1 指令寻址和数据寻址
指令寻址:寻找下一条需要执行的指令 数据寻址:寻找本条指令的数据地址
1. 指令寻址
指令寻址有两种方式:顺序寻址、跳跃寻址
- 顺序寻址:通过程序计数器PC自动加1,自动形成下条指令的地址
- 跳跃寻址:通过转移类指令实现。跳跃的结果是当前指令修改PC值,下一条指令依然由PC值给出
2. 数据寻址
数据寻址的方式比较多,为了区别各种方式,通常在指令中设置一个字段表示寻址方式
操作码 | 寻址特征 | 形式地址A |
---|
4.2.2 常见的数据寻址方式
1. 隐含寻址
例如单地址指令就不给出第二操作数的地址,而规定ACC作为第二操作数地址,指令显式指出第一操作数的地址。
隐含寻址优点:缩短指令字长 缺点:需要增加存储操作数或隐含地址的硬件
2. 立即(数)寻址
3. 直接寻址
优点:指令在执行阶段仅访问一次主存,不需要专门计算操作数的 缺点:A的位数决定了操作数的寻址范围,操作数的地址不易修改
4. 间接寻址
间接寻址是相对直接寻址而言的, 间接寻址可以是一次间接寻址,也可以是多次间接寻址
优点:可以扩大寻址范围(可以让EA的位数大于A的位数) 缺点:在指令执行阶段需要多次访存,降低了指令执行速度
间接寻址方式不常用,一般问到扩大寻址范围时,指的是寄存器间接寻址
5. 寄存器寻址
优点:指令执行速度快,无需访问主存;寄存器数量少,可以缩短指令字长 缺点:寄存器价格昂贵,计算机中寄存器个数有限
6. 寄存器间接寻址
寄存器 R i R_i Ri中给出的是操作数所在主存单元地址,即EA=( R i R_i Ri)
寄存器间接寻址的特点是:比一般间接寻址速度快,但指令执行阶段需要访问主存
7. 相对寻址
优点:操作数的地址不固定,随PC值的变化而变换,和指令地址之间总是相差一个固定值,。相对寻址广泛应用于转移指令
8. 基址寻址
基址寻址是 基址寄存器可用专用寄存器或通用寄存器
基址寄存器是面向操作系统的,内容由操作系统或管理程序确定,主要用于解决程序逻辑空间与存储器物理空间的无关性。
优点:扩大寻址范围(基址寄存器的位数大于A的位数);
9. 变址寻址
变址寄存器是面向用户的,程序执行过程中, 优点:扩大寻址范围;适合编制循环程序
10. 堆栈寻址
堆栈是存储器中一块特定的后进先出(LIFO)原则管理的存储区;区域中读/写单元的地址用特定寄存器给出,称为堆栈指针寄存器SP
硬堆栈:硬件实现(寄存器 软堆栈:主存中划分出一段区域用来做堆栈
采用堆栈结构的计算机系统中,大部分指令表面上都表现为无操作数指令的形式,操作数地址隐含使用SP
- 指令系统中采用不同寻址方式的目的是:缩短指令字长,扩大寻址空间,提高编程灵活性
- 指令中地址码为A,变址寄存器为X。则变址间址寻址方式的操作数的有效地址EA=((X)+A)
- 相对寻址方式中,指令提供的相对地址实质上是:以下条指令在内存中首地址为基准的偏移量
- 多道程序设计中,最重要的寻址方式是:相对寻址
- (14真题)某计算机有16个通用寄存器,采用32位定长指令字,操作码字段8位,Store指令的源操作数和目的操作数分别用寄存器直接寻址和基址寻址方式,基址寻址方式可以用任意通用寄存器,偏移量用补码表示,则Store中偏移量的取值范围? 解:16个寄存器需要4位指出,那么偏移量有32-8-4-4=16位,补码表示,因此取值范围-216~216-1
- 相对寻址的指令占3B,第一字节为操作码,第二三字节为相对位移量(补码表示),数据在存储器中采用以低字节为字地址的存放方式。若PC当前值为240(十进制),要求转移到290(十进制),则转移指令的第二三字节的机器码是: 解:取出当前指令后,PC的值应该是240+3=243,那么偏移量47=32+15,补码为 0010,1111 数据在存储器中采用低字节为字地址,那么是,因此第二三字节机器码为:F2H
4.3 程序的机器级代码表示
22年大纲新增
4.3.1 常用汇编指令介绍
1. 相关寄存器
x86处理器中有8个32位通用寄存器,如图。
- 为了向后兼容,EAX、EBX、ECX和EDX的高两位字节和低两位字节可以独立使用,E表示Extend
- EAX的低两位字节称为AX,AX的高低两位又称为AH和AL
- 除了EBP和ESP,其余几个寄存器的用途比较随意
2. 汇编指令格式
一般有两种不同的汇编格式:AT&T和Interl格式,其区别主要如下:
AT&T格式 | Intel格式 | |
---|---|---|
大小写问题 | 只允许用小写字母 | 大小写不敏感 |
操作数位置 | 第一个为源操作数,第二个为目的操作数 | 第一个为目的操作数,第二个为源操作数 |
前缀 | 寄存器前需要加前缀%,立即数需要加前缀$ | 寄存器和立即数都不需要加前缀 |
内存寻址 | 使用"(“和”)" | 使用"[“和”]" |
处理复杂寻址方式 | disp(%edx,%eax,2)分别表示偏移量,基址寄存器,变址寄存器和比例因子。表示M[R[edx]+R[eax]*2+8] | 对应的Intel格式是:[edx+eax*2+8] |
指定数据长度方面 | 指令操作码后紧跟一个字符,表示操作数大小,例如b表示字节,w表示字,l表示双字 | Intel语法类似,在操作码后面显式指出byte ptr / word ptr 或 dword ptr |
由于32位和64位体系结构都是16位扩展来的,因此用word(字)表示16位
3. 常用指令
以下是操作数的标记:
<reg>
:表示任意寄存器,若其后带有数字,则指定其位数,例如<reg32>
表示32位寄存器<mem>
:表示内存地址,例如[eax]
<con>
:表示8、16或32位常数,若其后带有数字,则指定其位数,例如<con8>
表示8位常数
1. 数据传送指令
mov
指令:将第二个操作数(寄存器的内容、内存中的内容或常数值)复制到第一个操作数(寄存器或内存)。但
对于Intel格式的指令,第二个操作数是源操作数,第一个操作数是目的操作数
mov <reg>, <reg> # 寄存器到寄存器
mov <reg>, <mem> # 内存到寄存器
mov <mem>, <reg> # 寄存器到内存
mov <reg>, <con> # 常数到寄存器
mov <mem>, <con> # 常数到内存
mov eax, ebx # 将ebx复制到eax
mov byte ptr [var], 5 # 将5保存到var指示的内存地址的一字节中
push
指令:将操作数压入内存的栈,常用于函数调用。
push <reg32>
push <mem>
push<con32>
push eax # eax压栈
push [var] # var值指示的内存地址的4字节值压栈
pop
指令:与push
指令相反,执行出栈工作,
pop edi # 弹出栈顶元素送到寄存器edi中
pop [ebx] # 弹出栈顶元素,送到ebx指示的内存地址的4字节中
2. 算术和逻辑运算指令
add/sub
指令:add
指令将两个操作数相加,结果保存到目的操作数中;sub
指令将两个操作数相减,结果保存到目的操作数中。
对于Intel格式的指令,目的操作数是第一个操作数
add/sub <reg>, <reg> # 寄存器到寄存器
add/sub <reg>, <mem> # 内存到寄存器
add/sub <mem>, <reg> # 寄存器到内存
add/sub <reg>, <con> # 常数,寄存器
add/sub <mem>, <con> # 常数,结果保存在内存中
sub eax, 10 # eax = eax-10
add byte ptr [var], 10 # var指向内存地址中的一字节加上10,存入var指示的内存地址的字节中
inc/dec
指令:分别表示将操作数自加1,自减1
inc/dec <reg> # 寄存器
inc/dec <mem> # 内存
dec eax # eax = eax-1
inc dword ptr [var] # var指示的内存地址的4字节值自加1
imul
指令:带符号乘法,有两种格式:
- 两个操作数相乘,结果保存在源操作数中(Intel格式的第一个操作数)
- 三个操作数,将第二第三操作数相乘,结果保存在第一操作数中,
imul <reg32>, <reg32>
imul <reg32>, <mem>
imul <reg32>, <reg32>, <con>
imul <reg32>, <mem>, <con>
imul eax. [var] # eax = eax*[var]
imul esi, edi, 25 # esi = edi*25
乘法操作结果可能溢出,此时编译器置溢出标志OF=1,使CPU调用溢出异常处理程序
idiv
指令:带符号整数除法,的内容(64bit整数),操作结果有两部分,商送到eax,余数送到edx(结合除法运算)
idiv <reg32>
idiv <mem>
idiv ebx
idiv dword ptr [var]
and/or/xor
指令:分别是逻辑与、或、异或,用于操作数的位运算,结果保存在目的操作数中
and/or/nor <reg>, <reg>
and/or/nor <reg>, <mem>
and/or/nor <mem>, <reg>
and/or/nor <reg>, <con>
and/or/nor <mem>, <con>
and exa, 0fH # eax = eax && 0fH
xor edx, edx # edx = edx ^ edx = 0
not
指令:位翻转指令,即操作数的每一位都翻转,0变1,1变0
not <reg>, <mem>
not <mem>, <reg>
not byte ptr [var] # var指示的内存地址的一字节所有位翻转
neg
指令:取负指令
neg <reg>
neg <mem>
neg eax # eax = -eax
shl/shr
指令:逻辑左移/右移指令,第一个操作数表示进行移位的数,第二个操作数表示移位的位数
shl/shr <reg>, <con8>
shl/shr <mem>, <con8>
shl/shr <reg>, <cl>
shl/shr <mem>, <cl>
shl eax, 1 # eax值左移一位,相当于*2
shr ebx, c1 # ebx右移n位,n为cl中的值,相当于除以2^n
3. 控制流指令
x86处理器维持一个指示当前执行指令的指令指针IP,当一条指令执行后,该指针自动指向下一条指令。 IP寄存器不能直接操作,但可以用控制流指令更新。通常用标签指示程序中的指令地址。在x86汇编代码中,可以在任何指令前加上标签:
mov esi, [ebp+8]
begin: xor ecx, ecx
mov eax, [esi]
此时begin
指示了第二条指令
jmp
指令:控制IP转移到label
所指示的地址
jmp <label>
jmp begin # 转移到begin标记的指令执行
j+condition
指令:条件转移指令,根据CPU状态字中的一系列条件状态转移
je <label> # euqal 相等时转移
jne <label> # not equal
jz <label> # zero 等于0时转移
jg <label> # greater 大于时转移
jge <label> # greater or equal
jl <label> # less 小于时转移
jle <label> # less or equal
cmp eax, ebx
jle done # 如果eax <= ebx,则跳转到done,否则执行下一条指令
cmp/test
指令:cmp
用于比较两个操作数的值,。 这两类指令都不保存操作结果,而是根据操作结果设置CPU状态字中的条件码
cmp/test <reg>, <reg>
cmp/test <reg>, <mem>
cmp/test <mem>, <reg>
cmp/test <reg>, <con>
cmp
和test
经常和j+condition
指令搭配使用
cmp dword ptr [var], 10
jne loop # 相等则顺序执行,否则跳转到loop处
test eax, eax # 测试eax是否为0
jz xxxx # 为0则设置标志ZF。跳转到xxxx处执行
call/ret
指令:分别用于实现子程序的调用及返回
call <label>
ret
call
首先将当前执行指令地址入栈,然后无条件转移到label
指示的指令。 ret
指令实现子程序的返回,弹出`栈保存的指令地址,然后无条件地转移到指令地址处执行
4.3.2 过程调用的机器级表示 TODO
4.3.3 选择语句的机器级表示 TODO
4.3.4 循环语句的机器级表示 TODO
4.4 CISC和RISC的基本概念
指令系统朝着两个截然不同的方向发展
- 增强原有指令的功能,设置更加复杂的新指令,实现软件功能的硬化。这类机器称为复杂指令系统计算机(CISC,C-Complex),典型的是x86架构计算机
- 减少指令种类,简化功能,提高指令的执行速度。这类机器称为精简指令系统计算机(RISC),例如ARM架构
4.4.1 CISC
- 指令系统复杂庞大,指令数目多
- 指令长度不固定,格式多,寻址方式多
- 可以访存的指令不受限制
- 各种指令执行时间相差很大
- 控制器大多数采用微程序控制,有些指令太复杂,无法使用硬连线控制
4.4.2 RISC
- 指令长度固定,格式少,寻址方式少
- ,其余指令的操作都在寄存器之间进行
- CPU中通用寄存器的数量相当多
- ,大部分指令在一个时钟周期内完成
- ,以减少程序执行时间
4.4.3 CISC和RISC对比
- RISC更能充分利用芯片面积。
- RISC运算速度更高
- RISC便于设计,可以降低成本,提高可靠性
- RISC有利于编译程序代码优化
- 有利于实现指令流水线的是:指令格式规整且长度一致、指令和数据按边界对齐存放、只有Load和Store指令才能对操作数进行存储访问