工程师在设计指令集体系结构时,将某些二进制代码指定为指令时会遵循什么程序或协议(如果有)。例如,如果我有一个说10110是加载指令的ISA,那么二进制数字是从哪里来的?是否从状态表中为表示加载操作的有限状态机建模?
编辑:经过更多研究,我相信我要问的问题涉及如何分配各种CPU指令的操作码。可以使用10011的操作码来指定ADD;一条加载指令可能指定为10110。为指令集分配这些二进制操作码有什么思路?
工程师在设计指令集体系结构时,将某些二进制代码指定为指令时会遵循什么程序或协议(如果有)。例如,如果我有一个说10110是加载指令的ISA,那么二进制数字是从哪里来的?是否从状态表中为表示加载操作的有限状态机建模?
编辑:经过更多研究,我相信我要问的问题涉及如何分配各种CPU指令的操作码。可以使用10011的操作码来指定ADD;一条加载指令可能指定为10110。为指令集分配这些二进制操作码有什么思路?
Answers:
在很多情况下,随着ISA的增长,选择是相当随意的,或者是基于“最适合的地方”。但是,MOS 6502是芯片的一个很好的例子,在该芯片中,ISA设计受尽了最大的努力,因为它试图从有限的晶体管中尽可能地挤压出来。
看看这个视频说明6502如何逆向工程,特别是从34:20开始。
6502是1975年推出的8位微处理器。尽管它的门数比Z80少60%,但速度却是Z80的两倍,尽管它受到更多限制(在寄存器等方面),但它还是用了优雅的指令集。
它仅包含3510个晶体管,这些晶体管是由一小群人在一些大的塑料板上爬行并手工拉出的,这些塑料板随后被光学收缩,形成了6502的各个层。
如下所示,6502将指令操作码和时序数据传递到解码ROM,然后将其传递到“随机控制逻辑”组件,其目的可能是在某些复杂情况下否决ROM的输出。
在视频中的37:00,您可以看到解码ROM的表,该表显示输入必须满足哪些条件才能为给定的控制输出获得“ 1”。您也可以在此页面上找到它。
您可以看到该表中的大多数内容在各个位置都有X。让我们举个例子
011XXXXX 2 X RORRORA
这意味着操作码的前3位必须为011,G必须为2;别的都无所谓。如果是这样,则名为RORRORA的输出将为true。所有ROR操作码均以011开头;但是还有其他说明也以011开头。这些可能需要由“随机控制逻辑”单元过滤掉。
因此,基本上,选择了操作码,以便需要彼此执行相同操作的指令在其位模式中具有某些共同点。您可以通过查看操作码表来看到这一点;所有“或”指令均以000开头,所有“存储”指令均以010开头,所有使用零页寻址的指令均采用xxxx01xx的形式。当然,某些指令似乎并不“适合”,因为其目的不是要具有完全规则的操作码格式,而是要提供功能强大的指令集。这就是为什么需要“随机控制逻辑”的原因。
我在上面提到的页面上说,ROM中的某些输出行出现了两次,“我们假设这样做是因为它们无法将所需行的输出路由到所需的位置,因此将同一行放在不同的位置再次定位。” 我可以想象工程师们一个接一个地绘制这些门,突然意识到设计中存在缺陷,并试图提出一种避免重新启动整个过程的方法。
这取决于ISA的年龄。
在手工设计的早期,甚至更多的情况是,当CPU由离散逻辑组装而成时,逻辑设计将首先出现并被广泛地最小化,然后,ISA位模式将是使该最小化所需的任何值。逻辑工作。
因此,可能会有一种特殊的控制信号模式,使某些多路复用器能够将ALU输出连接到GP寄存器文件的输入,还有一些控制信号指示ALU加,减,AND,OR等,还有一些地址位进入寄存器文件。这三组信号将在指令内形成字段。每个组将保持在一起,其详细含义从该单元(ALU等)的设计中产生,但是这些组可以以任何顺序排列,直到您设计指令解码器为止。(x86足够旧,如果您在正确的位置查看,您可以检测到其中一些-这不是全新的设计,而是借鉴了较旧的8080)
以后的ISA可能会被“清理”,并变得更加常规和易于使用,并且硬件有时会通过“微码”在它们和实际的硬件级控制信号之间进行转换。这些被称为“ CISC”或“复杂指令集编码”。x86“ Rep”指令前缀就是一个简单的例子-它使以下指令重复多次,从而省去了编写FOR循环的麻烦。
后来(在1980年代),人们又回到了更简单的直接编码样式(RISC-精简指令集编码),您可以在ARM处理器中看到这种样式。这是由于当时ASIC的尺寸较小,并且希望在其上放置32位CPU,因此没有足够的空间用于复杂的指令集解码器,以使整个CPU降至约20,000门。(这是暂时的性能提升,因为人们尚未开发出使CISC解码器更快的技术-大约在1995年,奔腾Pro就出现了。)
如今,这无关紧要-CPU一次读取几条指令,并投入数百万个晶体管对其进行解码,重新排序并一次执行尽可能多的指令,以加快可能是最早编写的程序的速度。 ISA的样式。
如果将类似的说明分组在一起,则会出现模式。这在ARM中非常明显,ISA手册实际上向您显示了指令字的哪一位对应于功能,寄存器选择等。但是对于X86也可以推断出来。
最终,操作码的“功能”部分进入某种二进制到单字节的解码器中,该解码器实际上会激活特定功能或流水线操作序列。它们通常与任何状态机的内容都不相关,除非我们考虑使用需要状态机解码的可变长度指令。
通常,您会将ISA分为功能组。(对于逻辑优化或整洁而言)有意义的是,互补对通过单个位更改(加载与存储)来区分,并且您具有影响解码决策树的某些位层次结构。
归根结底,为功能块分配任意位(与在指令中放置“数据”字段相反)只会对您的整体设计效率产生很小的影响-但是您可以选择很多方法根据您的感受,“优化” ISA编码是一个重要参数。
兰迪·海德(Randy Hyde)的出色著作(如果有些过时),在第3.3.4节“控制单元和指令集”及其后的章节中,x86指令集对组装艺术进行了详细介绍。
早期(冯·诺依曼之前)计算机系统中的程序通常“硬连线”到电路中。也就是说,计算机的布线确定了计算机将要解决的问题。为了更改程序,必须重新布线。一项非常艰巨的任务。计算机设计的下一个进步是可编程计算机系统,它使计算机程序员可以使用一系列插座和插头线轻松地“重新布线”计算机系统。计算机程序由一组孔(插槽)组成,每行代表程序执行期间的一个操作。程序员可以通过将电线插入所需指令的特定插座中来选择多个指令之一。
然后,他展示了相当吸引人的内容,并详细介绍了前几个插件代表指令的方式,接下来的插件对源和目标进行编码。当然,今天没有人再“插入”了,但是对于真正古老的ISA,操作码中的位基本上与以前的插入工作相同。
您最终得到这样的结果: