1.4 条件分支和循环的原理
程序的流程分为顺序执行、条件分支和循环三种。顺序执行就是按照地址的数值顺序执行指令。条件分支就是按照条件执行任意地址的指令。循环就是重复执行同一地址的指令。在顺序执行中,只要将程序计数器的值每次加1就可以了,但如果程序中存在条件分支和循环,机器语言的指令就可以将程序计数器的值设置为任意地址(不是不不1的值)。通过这样的方式,程序就可以返回之前的地址重复执行指令,或者跳转到任意地址从而实现分支。在这里,我们会展示一个条件分支的具体示例,循环也是以同样的原理通过设置程序计数器的值来实现的。
图1-5展示了内存中的一段程序,这段程序的功能是将内存中的值(这里是123)的绝对值输出到屏幕上。程序运行的起始位置是地址0100。随着程序计数器的值增加,程序执行到地址0102,此时如果累加器的值是正数,则会执行一条跳转到地址0104的指令(跳转指令)。由于此时累加器的值123是一个正数,所以地址0103的指令会被跳过,程序流程直接跳转到了地址0104。“跳转到地址0104”这条指令,实际上就是间接地执行了“将程序计数器的值设为地址0104”的操作。
图1-5 条件分支的程序示例(显示绝对值)
条件分支中所使用的跳转指令需要根据前一条指令的运算结果来判断是否进行跳转。在表1-1所列出的CPU寄存器中,有一个标志寄存器。标志寄存器会根据上次运算的结果,保存累加器和通用寄存器的值,无论值是正数、零还是负数,都会将其保存(也会保存溢出和奇偶校验的结果)。
CPU在每次读取数据或进行运算后,都会根据结果自动设置标志寄存器的值。在条件分支中,执行跳转指令之前会进行比较运算,CPU会根据标志寄存器的值来判断是否执行跳转指令。运算结果的正、零、负3种状态分别由标志寄存器中的3个比特来表示。图1-6是32位CPU(寄存器的长度为32比特)的标志寄存器示例。在这个标志寄存器中,第0个、第1个、第2个比特的值若为1,则代表运算结果分别为正数、零、负数。
图1-6 比较运算的结果存放在标志寄存器的3个比特中
CPU进行比较的方式非常有趣,请大家一定要了解一下。假设要将累加器中的值XXX和通用寄存器中的YYY进行比较,当执行比较指令时,CPU的运算器会在内部(暗中)执行“XXX-YYY”的减法运算,无论结果是正数、零,还是负数,都会保存到标志寄存器中。如果结果为正,则表示XXX大于YYY ;如果为零,则表示XXX等于YYY ;如果为负,则表示XXX小于YYY。也就是说,程序中的比较指令在CPU内部实际上是通过减法运算来实现的。怎么样,是不是很有趣呢?