一、条件分支和循环机制
我们都学习过高级语言。高级语言中的条件控制流程主要分为三种:顺序执行、条件分支、循环判断三种,顺序执行是按照地址内容顺序的执行指令。条件分支是根据条件执行任意地址的指令。循环是重复执行同一地址的指令。
● 顺序执行的情况比较简单,每执行一条指令程序计数器的值就是+1
● 条件和循环分支会使程序计数器的值指向任意的地址,这样一来,程序便可以返回上一个地址来重复执行同一指令,或者跳转到任意指令
下面以条件分支为例,说明程序的执行过程(循环也很相似)
条件循环的执行流程:
程序的开始过程和顺序流程是一样的,CPU从0100处开始执行命令,在0100和0101都是顺序执行,PC的值顺序+1,执行到0102地址的指令时,判断0106寄存器的数值大于0,跳转(jump)到0104地址的指令,将数值输出到显示器中,然后结束程序,0103的指令被跳过,这就和程序中if()判断是一样的,在不满足条件的情况下,指令会直接跳过。所以PC的执行过程也就没有直接+1,而是下一条指令的地址。
二、标志寄存器
条件和循环分支会使用到jump(跳转指令),会根据当前的指令来判断是否跳转,无论当前累加寄存器的运算结果是正数、负数还是零,标志寄存器都会将其保存(也负责溢出和奇偶校验)
溢出:(overflow):是指运算的结果超出了寄存器的长度范围
奇偶校验(parity check):是指检查运算结果的值是偶数还是奇数
CPU在运算时,标志寄存器的数值会根据当前运算的结果自动设定,运算结果的正、负和零三种状态由标志寄存器的三个位表示。标志寄存器的第一个字节位、第二个字节位、第三个字节位各自的结果都为1时,分别代表着正数、零和负数。
比较运算的标志寄存器示意图:
CPU的执行机制比较有意思,假设累加寄存器中存储的XXX和通用寄存器中存储的YYY做比较,执行比较的背后,CPU的运算机制就会做减法运算。而无论减法运算的结果是正数、零还是负数,都会保存到标志寄存器中。结果为正表示XXX比YYY大,结果为零表示XXX和YYY相等,结果为负表示XXX比YYY小。程序比较的指令,实际上是在CPU内部做减法运算。
三、函数调用机制
在高级语言编写的程序,函数调用处理也是通过把程序计数器的值设定成函数的存储地址来实现的。函数执行跳转指令后,必须进行返回处理,单纯的指令跳转没有意义。
实现函数跳转的例子:(程序调用示意图)
图中将变量a和b分别赋值为123和456,调用MyFun(a,b)方法,进行指令跳转。图中的地址是将C语言编译成机器语言后运行时的地址,由于1行C程序的编译后通常会变为多行机器语言,所以图中的地址是分散的。在执行完MyFun(a,b)指令后,程序会返回到MyFun(a,b)的下一条指令,CPU继续执行下面的指令。
函数调用和返回很重要的两个指令时 call 和 return 指令,再将函数的入口地址设定到程序计数器之前,call指令会把调用函数后要执行的指令地址存储在名为栈的主存内。函数处理完毕后,再通过函数的出口来执行return指令。return指令的功能是把保存在栈中的地址设定到程序计数器。MyFun函数在被调用之前,0154地址保存在栈中MyFun函数处理完成后,会把0154的地址保存在程序计数器中。这个调用过程如下:
函数调用中程序计数器和栈的职能:
在一些高级语言的条件或者循环语句中,函数调用的处理会转换成call指令,函数结束后的处理则会转换成return指令。