# 指令和程序 :::tip [前去观看第八集](https://bilibili.com/BV1EW411u7th?p=8) 观前提醒:在本篇文章中,我们所用到的 RAM 依旧是上一篇文章中用到的那个。 ::: ## 更多指令 ### 加法的对立面:SUB SUB 是减法,与 ADD(加法)指令相同,也要用两个寄存器 ### 跳跳跳:JUMP 如果你想改变指令顺序,或者跳过一些指令,那 JUMP 就是你的不二之选。JUMP 的作用是让程序跳转到新的位置。 JUMP 的底层实现方式:用指令后 4 位代表内存地址的值覆盖掉指令地址寄存器中的值(指令地址寄存器可以理解为记录当前内存地址的值的记事本,每完成一次指令,指令地址寄存器都会加一) #### JUMP 的好兄弟们 JUMP 的其中一个好兄弟,叫 JUMP_NEGATIVE。它只在 ALU 的负数标志为真时才进行跳转。 除此之外,还有 JUMO IF EQUAL(如果相等)、JUMP IF GREATER(如果更大) ### 请停下来:HALT HALT 指令是停止,如果没有它的存在,电脑会崩掉,快说谢谢 HALT 哥。 **HALT 很重要,能区分指令和数据,还能避免 CPU 不停运行下去后,去处理 STORE_A13 之后不是操作码的 0 而崩掉** ## 指令的综合运用 ### 无限的循环~ 循环~ 循环~ 在运行之前,我们要先把内存中的 3 和 14 两个数字都改成 1。 首先,把 LOAD_A 14 和 LOAD_B 15 中的两个 1 分别存入寄存器 A 和 B 中,然后 ADD B A 把寄存器 B 和 A 相加,结果放在寄存器 A 中。之后,使用 ATORE_A 13 的指令,把结果存在内存地址 13 中。接下来,就是本次主角的隆重登场——JUMP2!这条指令的意思是把指令地址寄存器的值改成 2,那么,我们就在一次的回到了 ADD B A,我们又一次的将 A 和 B 的值相加,然后又一次的遇到了 JUMP2。就这样,不断地循环且无法触发 HALT,这就是无限循环。 ![](%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221011201840.png) ### 如何利用 JUMP 的兄弟逃出循环 这一次,我们进行了微小的更改,比如说将 A 的值改成了 11,B 改成了 5,用 SUB 代替了 ADD,用到了 JUMP_NEGATIVE 指令,具体的更改如下图 ![](%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221011205418.png) 现在,让我们跟着 CPU 走一遍。到了 SUB B A,用 A 减 B 等于 6,将结果存在 A 中。因为 6 不符合 JUMP_NEGATIVE 的跳转条件,故进行下一条指令。下一条是 JUMP2,那就再次跳回 SUB,再用 A 减去 B 结果为 1,依旧不符合,继续重复。这一次有了改变,A 减 B 结果是-4,符合了 JUMP_NEG 5 的跳转条件,接下来直接跳转到第五条指令 ADD B A,将 A B 的结果相加并存到寄存器 A 中,再根据下一条的指令,把 A 的值存在内存地址 13 中。最后,碰到了 HALT。现在,我们的程序终于可以休息了。 ## 现代如何使用更多的指令 我们在这里假设的 CPU 都很基础,只有 4 位,只能操作 16 个地址。而现代的 CPU 有两种策略来增加能使用的指令。 ### 最粗暴的方法 —— 更多的位 第一种方法十分简单粗暴,直接用更多的位来代表指令,现代常有的是 32 位和 64 位。 ### 麻烦的技巧型 —— 可变指令长度 举个栗子,比如某个 CPU 用 8 位长度的操作码,如果看到 HALT 指令,HALT 不需要额外数据,那么会马上执行;看到 JUMP,它得知道位置值,这个值在 JUMP 后面,这叫**立即值** 这样设计,指令可以是任意长度,但会让读取阶段麻烦一些。 当然,这里要说明一下,我们拿来距离的 CPU 和指令集都是假设的,是为了展示核心原理。 最后再来展示一下我们的小美人 —— 4004 处理器 ![](%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20221011212254.png) ## 接下来 下一章,我们会讲到 CPU 更多的功能