五、存储元件
D锁存器
st为0时无响应(不影响存储和输出),st为1时存储并输出d。
D触发器
其实就是引入了上升沿触发的锁存器。
时钟信号上升沿:若st=1将存储并输出d,st=0时输出不变。第一个上升沿前输出0。
时钟信号下降沿:输出不变。
实现的关键:一是用两个锁存器分别缓存输入和输出。二是如何读取上升沿,我利用了门延迟。
DFF(st, d, cl) = latch(cl, latch((st & ~cl) & cl, d))
对于第一个问题:内层的latch是输入缓存,在上升沿时将d存入并输出到外层latch;外层latch是输出缓存,时钟为1时就存储并输出。
对于第二个问题:注意到(st & ~cl) & cl,仅从逻辑层面考虑输出一定为0;但是由于门延迟的存在,括号内的&先被计算。当时钟信号为0,st & ~cl = st;如果遇到上升沿则在短时间内转换为1,此时刚好被外面的与门捕获到,故该表达式结果为st。
但是这个方案(13个与非门)并不是最简的表达,展开两个锁存器合并其中的非门和复用项后,得到11个与非门的最简表达。这两种方案的门延迟都为9。
寄存器
一个n-bit寄存器由n个DFF并联组成,可以并行执行,因此速度很快。
程序计数器
时钟信号为0时:
st=0时,计数器+1;
st=1时,计数器设为X;
时钟信号上升沿:
用计数器的当前值更新输出。
值得注意的是,为了在后续CPU架构整合时能够同步时钟,因此更新输出的时钟信号都统一为上升沿。
实现:用一个程序寄存器存储计数器的存储值(因为输入X是16位,所以用16位寄存器;如果输入为1bit,仅需1个DFF)。由于不论st为何,计数器的值都会被更新,因此程序寄存器的st位常1。
扩展:可见一个n-bit程序计数器由一个n-bit程序寄存器和一个2^n to 1选择器组成。
RAM随机存储器
用于存储程序指令,断电会丢失数据。ad指定访问的寄存器序号,st决定是否将X写入ad指定的寄存器,在cl上升沿更新输出。
对于给定n和m(必须是2的指数),由1 to n译码器->n组m位寄存器->m to 1多路选择器组成。
不难发现RAM的门延迟比寄存器略高,选择器和译码器的门延迟分别和m和n的对数成正比。
六、处理器
复合存储器
本CPU需要一个地址寄存器A和目标数寄存器D以及从RAM中对A取址的RAM,于是得到该符合寄存器。
输入:
X待存储的数据值;
目标存储位置(三选一):a d 为1时分别存到A和D寄存器,*a为1时存到RAM中寻址寄存器A所在的位置。
ALU指令译码器
输入:
16位指令I,指令中包含了对ALU的计算逻辑和标志位,以及分支逻辑,以及目的寄存器。
右操作数A和A,根据I的第12位选择右操作数是A还是A。
左操作数D。
输出:
R是ALU输出的结果,a d *a 是三选一(目标寄存器位置,容易联想到可以连到复合存储器的输入),j为结果R根据指令I中分支逻辑的计算结果(用于实现条件跳转)。
控制单元
在ALU指令译码器的基础上,引入赋值指令:若I最高位为1,则和ALU指令译码器完全相同;如果指令I的最高位为0,则将I看作一个数直接作为R输出,这个数传输到寄存器A,并且j设置为0。
不难注意到,由于这种指令定义方式,赋值范围为[0x0, 0x7fff],因为符号位被占用,不能表示负数。
计算机(CPU模型)
CPU的运行流程总体而言就是:取指-译码-执行-访存-写回。
取指:从程序计数器取出指令地址,从ROM(只读存储器)取出该地址处存储的指令,并传输给指令译码器(nandgame中将其合并到控制单元)。
译码:通过指令译码器将16位指令转换为操纵各运算单元的信号。
执行:控制器完成该任务,控制信号有两大类,传输数据(直接送到A寄存器)和执行计算(ALU完成)。
访存:对于计算指令,从复合存储器(寄存器和RAM)取出操作数供给ALU计算。
写回:执行完的结果,写回到符合存储器指令指定的目标位置。并通过分支逻辑判断结果是否符合指令所需的跳转条件,如果不跳转,程序计数器+1(执行ROM的下一条指令);否则,将地址寄存器A的值存到程序计数器(下次跳转到ROM中A处的指令,适用于无/有条件跳转指令如JGT L1)。
IO
st和cl同时为1时,读取X指定位以切换灯泡的开关状态。联系前文中写值都是cl=0时实现,cl=1时不改变数据值。猜测是为了保证Input读取时的数据稳定。
按钮按下时,设置输出位。
总结
至此,上篇-硬件部分已经全部完成。