- 补充知识
- 取指
- 译码
- 执行
- 回写
- 总结
=======================================
补充知识:
不知道你能不能看懂汇编指令,如:
mov ax,0800H ; 将内存地址 0B800H 写入 ax 寄存器
add ax,ds:[6] ; 计算 ax + ds:[6],
并将值更新到 ax 寄存器
取指:
CPU的控制电路将 PC(Program Counter )程序计数器 , 通过内部总线传递到 MAR (Memory Address Register 内存地址寄存器)。
MAR通过地址总线将指令地址发送到存储器内的MAR,与此同时 CPU的控制电路通过控制总线将存储器的控制逻辑电路状态转变为 Read状态。接下来存储器的控制逻辑电路将MAR内的地址通过地址译码器进行“翻译”找到地址。
地址 数据
0000 01010101
0001 10101010 ;这个数据将被读取
,因为CPU内的指令存储器 PC -> 0001
并将0001地址对应的数据通过内部总线传递给 MDR (Memory Data Register)寄存器通过数据总线进行数据的传输,此时存储器的控制逻辑电路通过控制总线给CPU一个反馈状态为 Ready,接下来CPU通过控制电路的检测将存储器传递过来的数据用对应的 MDR 寄存器进行存储。此外MDR的内容将要存储到 IR (指令寄存器)中。这样取指的过程就完了?
NO,最后一步得将 PC 指向下一个要执行指令的地址,或者说得更新 PC 程序计数器。
译码:
CPU通过控制电路将IR 里面的指令通过内部总线传输到 指令译码器 进行翻译成需要执行的代码。也就是说通过这个告诉CPU我该怎么做。
# 在 Linux 中我们可以通过反汇编的方式,
将 c 代码,机器码,汇编代码 共同展示出来;
机器码: 汇编:
10101010 ADD R0,[6]
;将 R0里面的值和内存地址为6(0110)的值相加并
更新到 R0寄存器中。
对于反汇编的一个举例:
Objdump -d -M intel -S test.o
if (r == 0)
3b: 83 7d fc 00 cmp DWORD PTR [rbp-0x4],0x0
3f: 75 09 jne 4a <main+0x4a>
{
a = 1;
41: c7 45 f8 01 00 00 00 mov DWORD PTR [rbp-0x8],0x1
48: eb 07 jmp 51 <main+0x51>
}
else
{
a = 2;
4a: c7 45 f8 02 00 00 00 mov DWORD PTR [rbp-0x8],0x2
51: b8 00 00 00 00 mov eax,0x0
}
这里有个印象即可。
执行:
通过译码阶段我们得知必须要到内存为 【6】对应二进制数 0110 的地方读取数据并写入到 CPU内 MDR 寄存器中,这一步骤和 取指 差不多。
将读取到数据的 MDR 和 R0 写入到 两个操作数寄存器 X 和 Y 中 ,进行计算。
注: 这里的 Z 是存储计算结果的,和旁边的 F 则是标志寄存器,如果计算产生溢出则标记为 1 。
如果对 F 的实现原理感兴趣可以看这篇博客:
《自己动手组件一个 ALU》
回写:
如上面的汇编代码,将计算的结果更新到 R0 中,则CPU得到指示将 Z 寄存器的数据写入到 R0 中。
到这回写的过程全部完成。
总结:
Q: 如果上面步骤全部执行完,那接下来是干啥呢?
A:再开始新一轮的取指啊!
绿茶经典语录:
到这,终于知道CPU小哥哥的历害了,没日没夜的忙,重复一件事,再这样操劳,妹妹会伤心的。