微处理器设计/指令译码器
指令译码器从内存中读取下一条指令,并将该指令的组成部分发送到必要的目的地。
对于每个机器语言指令,控制单元都会产生每个控制信号线上实现该指令(以及获取下一条指令)所需的脉冲序列。
如果幸运的话,在设计处理器时,你会发现许多控制信号可以从指令寄存器“直接译码”。例如,有时指令寄存器 IR 的几个输出位可以直接连接到 ALU 的“哪个函数”输入端。即使这些位在非 ALU 指令中具有完全无关的意义,只要 ALU 执行,例如,一个虚假的减法,而处理器其余部分正在执行一个存储指令,就可以了。
其余无法从指令寄存器中译码的控制信号——如果你不幸的话,所有控制信号——由控制单元生成,控制单元以[Moore 机][2]或[Mealy 机][3]实现。有很多不同的方法来实现控制单元。
如果设计了一个使用普林斯顿架构的处理器——你的处理器通常从用于读写数据的同一个单端口内存中提取指令——那么你就被迫让至少加载和存储至少需要两个时钟周期才能执行。(一个周期用于数据,另一个周期用于读取下一条指令)。(许多处理器都设计为“单周期执行”,无论是非常简单的哈佛架构处理器,还是复杂的、具有单独指令缓存的高性能处理器)。
RISC 机器背后的理念是,指令执行要保持极快的速度和简单性。因此,指令译码器(如果有的话)必须尽可能地简化。折衷方案是必须执行更多指令才能执行更复杂的机器功能。所有低级抽象必须在机器代码编译器中提供。
RISC 译码器通常有两种变体。
在第一种变体中,指令代码的位直接馈送到硬件组件,因此实际上根本没有译码器。所有定时要求必须通过仔细编程机器代码来满足,并且没有指令译码器的执行延迟。必要的控制线“波形”是直接由指令序列创建的。一旦指令出现,硬件就开始响应。指令集中的位直接代表硬件组件的实际物理控制。
第二种变体包括指令代码和硬件组件之间的一个简单(快速)译码器。这种译码通常由离散逻辑门实现。这个译码器的主要目的是允许“更简洁”的指令集表示。与直接变体一样,每条指令仍然代表一个单独的机器功能,但使用译码器通常会显着减少机器代码字中所需的位数。反过来,这可以允许在一条机器指令中启动多个硬件功能。
译码 CISC 指令字比 RISC 情况要困难得多,并且译码器复杂性的增加是人们选择在设计中使用 RISC 而不是 CISC 的常见原因。
CISC 译码器通常使用一个状态机,该状态机设置为一个随机长度的排序器。机器读取操作码字段以确定它是什么类型的指令以及其他数据值在哪里(如果需要)。指令字甚至可以逐段读取,因此可以在每个阶段做出决定,说明如何读取指令字的其余部分以及任何包含的数据。
与 RISC 译码器的情况相反,这个译码器会按顺序遍历机器硬件的多个状态。指令代码选择要执行的序列,排序器控制此执行的定时。此执行中的一个“步骤”可能包括从指令代码中获取更多输入,无论此输入是进一步的指令还是所需的数据值。
也许理解这种译码器类型最简单的方法是将其视为一个非常宽的控制存储 ROM。此 ROM 中的程序是译码器/排序器的微代码。指令寄存器的部分用于形成此 ROM 的地址的一部分。地址的几位来自 ROM 本身。ROM 的大多数输出用于控制系统硬件。
反馈地址部分形成一个循环,该循环将按照编程到 ROM 中的方式逐步遍历随机序列。此循环的运行速度与 ROM 允许的访问时间一样快,通常是一个系统时钟。反馈地址通常被编程为在排序器的每个后续状态递增 1。反馈位的数量决定了微码序列的最大长度。
管道寄存器在每个时钟周期都锁定控制存储 ROM 的所有输出位。
每个时钟周期,管道寄存器都会锁定一组新的位。
排序器的输出有两个部分
控制位发送到处理器的硬件组件。反馈到控制存储 ROM 的一些地址输入的“微 PC”。有些人将进位标志硬连线到控制存储 ROM 的一个地址输入。
每次从主内存中获取新的操作码时,通常将微 PC 的高位加载操作码,并将微 PC 的低位复位为零。(为了便于调试,一些设计人员将操作码加载到单独的指令寄存器 IR 以及微 PC 寄存器中,至少在初始原型中是这样。一旦设计调试完毕,可能会发现 IR 或微 PC 寄存器或两者中的某些或所有位从未使用过,因此可以从最终设计中删除)。在执行指令期间,每个时钟周期,管道寄存器都从控制存储器加载一个新的微 PC 地址,并从控制存储器加载一组新的控制位。通常,编写微程序的人(刻录到控制存储 ROM 中)将该 ROM 的下一地址输出位设计为在该操作码的最初几个周期中按顺序递增。然后,每个“正常”操作码的微程序最终都会跳转到控制存储 ROM 的一个公共部分,该部分处理获取下一条指令。