CPU 工作 (2)
Source: Dev.to
CPU 如何实现循环和条件
虽然 CPU 只对数字进行算术运算,但它仍然可以通过特殊的 分支指令 来改变执行流,从而实现循环和条件分支。
条件跳转 (JZ)
一种典型的条件跳转指令是 JZ(zero 为真时跳转)。当特定标志位(零标志)被置位时,它会把控制权转移到标记的地址。
LOAD A, 1
LOAD B, 1
CMP A, B ; compare A and B
JZ exit ; jump to `exit` if the comparison result is zero
STOREM A, 0 ; store register A to memory
exit:
HALT
JZ 检查什么?
JZ 不检查标签本身。它查看 Zero 标志 (Z),该标志由前面的 CMP 指令设置。如果标志为真(1),CPU 就跳转到标签标记的地址。
CMP 更新的标志
CMP(比较)指令会把一个操作数从另一个操作数中减去 但不保存结果;它只会更新状态标志:
| 标志 | 含义 |
|---|---|
| Z(Zero) | 如果减法结果为零,则置为 1 |
| N(Negative) | 如果结果为负,则置为 1 |
在真实的 CPU 中,这些标志位存放在状态/标志寄存器中;在模拟器里可以用一个简单的结构体来保存。
循环示例
循环可以由条件跳转 (JZ) 和无条件跳转 (JMP) 组合而成。
LOAD A, 4
LOAD B, 1
LOAD C, 1
loop:
SUB A, B ; A = A - B
CMP A, C
JZ exit ; if A == C, exit loop
JMP loop ; otherwise repeat
exit:
HALT
JZ实现条件退出。JMP无条件跳回循环起始处。
如果零标志未被置位,执行会继续到 JMP,它始终把控制权转回 loop。
CMP 的实现(模拟)
// Subtract operandB from operandA and set flags
int temp = reg.r[inst.operandA] - reg.r[inst.operandB];
flag.zero = (temp == 0);
flag.negative = (temp < 0);
programCounter++; // advance to next instruction
关键规则:CMP 不能修改任何寄存器或内存;它只更新标志位。
其他跳转指令
根据 CPU 设计的不同,还可能提供其他条件跳转指令,例如:
JG– 大于时跳转(Z = 0 且 N = 0)JL– 小于时跳转(N = 1)JNZ– 非零时跳转(Z = 0)
这些指令使用 CMP 或类似指令设置的相同标志位。
高层代码到 CPU 分支的映射
考虑下面的 C 风格条件语句:
int valueA = 2;
int valueB = 3;
if (valueA == valueB) {
// do stuff
}
在机器层面,编译器通常会生成:
CMP valueA, valueB– 根据valueA - valueB设置标志位。JZ label– 如果零标志被置位(即两值相等),跳转到代码块。
因此,即使是复杂的高级结构,也会归结为一系列设置标志的比较指令和分支指令。