目录
- 目录
- 寻址
- 合并
- JUMP:重要的操作码
- 条件跳转:计算机初步
- 零锁存器(Zero latch)
- Conditional Jump
- 循环操作
上回我们构造了一个可以自动进行加法操作,并且可以自动存储的机器;虽然结构看上去很清晰,但是代码与数据分别存在两个RAM中,在另一个角度看来是有些冗余的;我们可以尝试着把代码与数据共同存放在一个RAM里,尽管在管理不当的情况下会造成比较严重的问题,但是在清晰的操作下,它的灵活性得到了巨大的改善!这是可以接受的。
寻址
在之前的自动操作器(姑且这么叫吧),操作码与数据地址是一一对应的,它们通过计数器相关联。一个操作码无法“越位”对与它不匹配的地址数据进行操作;如果我们希望改变这种笨拙的状态,或许可以试试把地址存在操作码存储中。
改进前 | 改进后 | |||||
代码地址 | 代码 | 代码地址 | 代码 | 代码地址 | 代码 | |
0000h | Load | 0000h | Load | 0004h | 00h | |
0001h | Add | 0001h | 00h | 0005h | 01h | |
0002h | Store | 0002h | 00h | 0006h | Store | |
0003h | Halt | 0003h | Add | … | … |
每个指令后跟着要操作的地址,原有的结构中,由计数器指向数据存储的通路将被抹去;而由代码输出端提供。但是因为一个RAM要按顺序输出三个数据,一方面我们的速度下降了(一个时钟周期能完成的任务变成了需要四个周期执行),另一方面对控制信号也需要进行更复杂的改变。
合并
更进一步,我们可以把两个RAM合并,以此提高利用率!在这些精巧的设计中,时序是非常重要的,控制信号仍需要花费一定的功夫来实现。下图仅仅是操作控制方面的电路图,省略了数据处理方面的电路图,当然二者有很多部件是共用的。
但是仍然存在问题;我们无法预估要执行多少的指令才能完成一项任务,也就是说,随着指令的增多,存放指令的地址可能会增加到数据存储的地址,甚至覆盖之;如果我们想高效的合并两个RAM,我们或许还得给指令集加上一个Jump操作。
JUMP:重要的操作码
jump和普通的操作不同,我们必须保证跳转之后,电路能“智能”的按原有的规律(一个操作,两个地址)继续执行下去,仿佛“原本就该这样”。也就是说,我们或许得对根源-计数器进行一些额外的操作了。
还记得之前的改进版边沿触发器吗
其实只要稍加改进,就可以“强行”改变计数器的值了;
置位为1,复位为0,A输入进触发器;置位为0,复位为0,A无法输入;复位为1,清零;
于是我们又会得到这样的电路图
条件跳转:计算机初步
Jump大大改进了自动操作机的功能,而更进一步的Conditional Jump将真正让我们的机器初显“智能”;也就是loop,循环操作的基础;
像高级语言中的if条件语句要实现在电路中还是要从基本的做起
零锁存器(Zero latch)
把一位边沿触发锁存器和加法器进行如下联接,仅当八位加法器输出0时,DI才为1;把零标志位(Zero flag)与Jump控制信号进行一定的组合,就可以很容易得到Jump if Zero
Conditional Jump
将Zero latch 的Zero flag 作为控制信号的一员通过不同方式接近控制电路,可以得到四个Conditional Jump指令
Jump If Zero、Jump If Carry、Jump If Not Zero、Jump If Not Carry;
很容易想到,只要设定一个数A,每次执行后A–1,当A为零时过程就执行了A次;再每次-1后使用Jump If Not Zero指令,就实现了循环操作!!!
循环操作
别忘记Halt的操作码是FFh,如果其作为数据与任意数据相加后,就相当于-1,也即是说我们的A-1其实只需要与FFh相加即可!并不需要而外设置一个地址存储1;
循环操作是计算器与计算机的一个重大区别,行至此处,我们的自动操作器已经离cpu不远啦。
最后再来看看我们的指令集
操作 | 操作码 |
Load(加载) | 10h |
Store(保存) | 11h |
Add(加法) | 20h |
Subtract(减法) | 21h |
Add with Carry(进位加法) | 22h |
Subtract with Borrow(借位减法) | 23h |
Jump(转移) | 30h |
Jump If Zero(零转移) | 31h |
Jump If Carry(进位转移) | 32h |
Jump If Not Zero(非零转移) | 33h |
Jump If Not Carry(无进位转移) | 34h |
Halt(停止) | FFh |