一条汇编指令如何转化为 CPU 上的电压变化?
Posted
技术标签:
【中文标题】一条汇编指令如何转化为 CPU 上的电压变化?【英文标题】:How does an assembly instruction turn into voltage changes on the CPU? 【发布时间】:2011-04-11 23:38:40 【问题描述】:在过去的 3 到 5 年里,我一直在使用 C 和 CPython。考虑一下我的知识基础。
如果我要对支持它的处理器使用诸如MOV AL, 61h
之类的汇编指令,那么处理器内部究竟是什么来解释此代码并将其作为电压信号发送?这么简单的指令怎么可能执行?
当我尝试想到 MOV AL, 61h
甚至 XOR EAX, EBX
中包含的大量步骤时,Assembly 甚至感觉像是一门高级语言。
编辑:我读了一些 cmets 询问为什么当 x86 系列在嵌入式系统中不常见时我把它作为嵌入式。欢迎来到我自己的无知。现在我想,如果我对此一无所知,那么可能还有其他人对此一无所知。
考虑到你们都为答案付出的努力,我很难选择一个最喜欢的答案,但我觉得有必要做出决定。没有受伤的感觉,伙计们。
我经常发现,我对计算机了解得越多,我发现自己真正了解的就越少。感谢您让我对微码和晶体管逻辑敞开心扉!
编辑#2:多亏了这个帖子,我才明白为什么XOR EAX, EAX
比MOV EAX, 0h
快。 :)
【问题讨论】:
顺便说一句,这是一个很棒的问题。令人惊讶的是,很少有开发人员知道晶体管如何进入他们的世界,或者费心去研究。你正在意识到自己的无知,这会让你成为非常的好伙伴。 真正让你头疼的是如何电路制造与已有 100 年历史的摄影技术相差不远。 re: 最后一段:如果你真的想知道在各种现代 Intel 和 AMD 微架构(除了代码大小)上异或归零更好的所有方法,请参阅 this answer。 【参考方案1】:如果没有整本书,就不可能详细解释整个系统,但这里是对简单计算机的高度概述:
最底层是物理和材料(例如由掺杂硅制成的晶体管)。 使用物理和材料,您可以推导出NAND logic gate。 使用 NAND 门,您可以派生所有其他基本逻辑门(AND、OR、XOR、NOT 等),或者为了提高效率,直接从晶体管构建它们,包括具有超过 2 个输入的版本。 使用基本逻辑门,您可以推导出更复杂的电路,例如adder、multiplexer 等。 同样使用基本逻辑门,您可以导出有状态的数字电路元素,例如 flip flop、clock 等。 使用更复杂的状态电路,您可以推导出更高级别的片段,例如counters、memory、registers、arithmetic-logic-unit 等。 现在您只需将高级组件粘合在一起即可: 内存不足 通过使用多路复用器等将值分派到适当的位置(例如 ALU 或内存),将值解释为指令。(基本指令类型是从内存读取到寄存器,从寄存器写入-into-memory、perform-operation-on-registers 和 jump-to-instruction-on-condition。) 下一条指令重复该过程要了解汇编指令如何导致电压变化,您只需了解每个级别如何由以下级别表示。例如,一条 ADD 指令将导致两个寄存器的值传播到 ALU,ALU 具有计算所有逻辑运算的电路。然后另一侧的多路复用器从指令中接收到 ADD 信号,选择所需的结果,该结果会传播回其中一个寄存器。
【讨论】:
您通常不会仅从 NAND 构建所有电路;您使用了一些不完全遵循的组合(为了提高效率)。任何 CPU 中最重要的一个部分是您忽略的部分:锁存器,通常由时钟信号驱动。 (它也是 CPU 寄存器如何工作的核心。) @Donal 这是一个简单的计算机,而不是一个实用的计算机。我还必须在其他级别上删减很多信息。另外,我说的是触发器而不是闩锁。 @Strilanc,你忘了在“计数器、内存、寄存器等”之后提到 FSM。那是墙后的“大脑”!!!当然,所有硬件系统都不过是“DATAPATH”(计数器、存储器、寄存器、多路复用器等)和“FSM”(组合逻辑 + 触发器)。【参考方案2】:我最近开始阅读 Charles Petzold 的《代码》一书,到目前为止,这本书涵盖了我认为您会感兴趣的所有内容。但是我还没有完全通读,所以在购买/借阅之前先翻阅这本书。
这是我相对简短的回答,而不是 Petzolds……希望与您的好奇心一致。
你听说过我假设的晶体管。最初使用晶体管的方法是用于晶体管收音机之类的东西。它基本上是一个放大器,将漂浮在空气中的微小无线电信号馈入晶体管的输入端,该晶体管打开或关闭旁边电路上的电流。然后你用更高的功率连接那个电路,这样你就可以接收一个非常小的信号,放大它并将其馈入扬声器,例如收听广播电台(还有更多的事情是隔离频率并保持晶体管平衡,但是你明白我希望的想法)。
现在晶体管的存在导致了一种将晶体管用作开关的方法,就像电灯开关一样。收音机就像一个调光开关,你可以把它调到任何地方,从一直开到一直关。非调光灯开关要么全部打开,要么全部关闭,开关中间有一个神奇的地方可以切换。我们在数字电子产品中使用晶体管的方式相同。取一个晶体管的输出并将其馈入另一个晶体管输入。第一个晶体管的输出肯定不是无线电波那样的小信号,它迫使第二个晶体管一直打开或关闭。这导致了TTL或晶体管晶体管逻辑的概念。基本上你有一个晶体管驱动一个高电压,或者我们称之为 1,然后在它上吸收一个零电压,我们称之为 0。然后你用其他电子设备安排输入,这样你就可以创建与门(如果两个输入是 1,则输出为 1),或门(如果一个或另一个输入为 1,则输出为 1)。反相器、NAND、门、NOR 门(一个或带有反相器)等。曾经有一本 TTL 手册,你可以购买 8 个左右的引脚芯片,这些芯片有一个或两个或四个某种门(NAND、NOR、 AND等)内部功能,两个输入和一个输出。现在我们不需要那些用数百万晶体管创建可编程逻辑或专用芯片更便宜的东西。但是我们仍然在硬件设计中考虑 AND、OR 和 NOT 门。 (通常更像是 nand 和 nor)。
我不知道他们现在教什么,但概念是相同的,对于内存,触发器可以被认为是这些 TTL 对 (NANDS) 中的两个连接在一起,其中一个的输出连接到另一个的输入。就这样吧。这基本上是我们所说的 SRAM 或静态 ram 中的一个位。 sram 基本上需要 4 个晶体管。 Dram 或动态 ram 您自己放入计算机中的记忆棒每比特需要一个晶体管,因此对于初学者,您可以了解为什么 DRAM 是您购买千兆字节的东西。只要电源不熄灭,Sram 位就会记住您将它们设置为什么。当你告诉它时,Dram 开始忘记你告诉它的内容,基本上 dram 以第三种不同的方式使用晶体管,有一些电容(如电容器,不会在这里进入),就像一个微型可充电电池,一旦你给它充电并拔下充电器,它就会开始耗尽。想一想架子上的一排玻璃杯,每个玻璃杯上都有小孔,这些都是你的酒杯,你希望其中一些是杯子,所以你有一个助手来装满你想成为的杯子。那个助手必须不断地把水罐装满,然后往下走,让“一”位的杯子装满水,让“零”位的杯子保持空着。因此,任何时候您想查看您的数据是什么,您都可以通过查找绝对高于中间的水位为 1 和绝对低于中间的水位为零来查看并读取 1 和 0。所以即使打开电源后,如果助手不能让眼镜保持足够满以区分 1 和 0,它们最终会看起来像 0 并耗尽。这是每个芯片更多位的权衡。简短的故事是,在处理器之外,我们使用 dram 作为大容量内存,并且有辅助逻辑负责将 1 保持为 1,将 0 保持为 0。但是在芯片内部,例如 AX 寄存器和 DS 寄存器使用触发器或 sram 来保存您的数据。对于您知道的每一位(例如 AX 寄存器中的位),可能有成百上千或更多用于将这些位进出该 AX 寄存器。
您知道处理器以某种时钟速度运行,如今大约为每秒 2 GHz 或 20 亿时钟。想想时钟,它是由晶体产生的,另一个话题,但逻辑认为该时钟是一个电压,在这个时钟频率 2ghz 或其他任何情况下会变高和零高和零(gameboy 的进步是 17mhz,旧 ipod 大约是 75mhz,原装 ibm pc 4.77mhz)。
因此,用作开关的晶体管允许我们获取电压并将其转换为我们作为硬件工程师和软件工程师都熟悉的 1 和 0,甚至可以为我们提供 AND、OR 和 NOT 逻辑功能。我们有这些魔法水晶,可以让我们获得准确的电压振荡。
所以我们现在可以说,如果时钟是一个,并且我的状态变量说我处于获取指令状态,那么我需要切换一些门,以便我想要的指令的地址,在程序计数器中,在内存总线上熄灭,以便内存逻辑可以给我关于 MOV AL,61h 的指令。您可以在 x86 手册中查找此内容,并发现其中一些操作码位表示这是一个 mov 操作,目标是 EAX 寄存器的低 8 位,而 mov 的源是立即值,这意味着它在这条指令之后的内存位置。所以我们需要将该指令/操作码保存在某处,并在下一个时钟周期获取下一个内存位置。所以现在我们保存了 mov al, immediate 并且我们从内存中读取了值 61h,我们可以切换一些晶体管逻辑,以便 61h 的位 0 存储在 al 的位 0 触发器中,位 1 到位 1 等.
你问这一切是怎么发生的?想想一个 python 函数执行一些数学公式。您从程序的顶部开始,将一些作为变量输入的公式输入,您可以在程序中执行单独的步骤,这些步骤可能会在此处添加一个常量或从库中调用平方根函数等。在底部您返回答案。硬件逻辑以相同的方式完成,今天使用的编程语言看起来很像 C。主要区别在于您的硬件功能可能有数百或数千个输入,而输出是一位。在每个时钟周期,AL 寄存器的第 0 位都在使用一个庞大的算法进行计算,具体取决于您想要查看的距离。想想您为数学运算调用的平方根函数,该函数本身就是其中一些输入产生输出,它可能调用其他函数,可能是乘法或除法。所以你可能在某个地方有一点你可以认为是 AL 寄存器的第 0 位之前的最后一步,它的功能是:如果时钟为 1,则 AL[0] = AL_next[0];否则 AL[0] = AL[0];但是有一个更高的函数包含从其他输入计算的下一个 al 位,一个更高的函数和一个更高的函数,其中大部分是由编译器创建的,就像你的三行 python 可以变成数百或数千的汇编程序行。几行 HDL 可以变成成百上千甚至更多的晶体管。硬件人员通常不会查看特定位的最低级别公式来找出所有可能的输入以及计算所需的所有可能的 AND 和 OR 和 NOT,而不是您可能检查程序生成的汇编程序。但如果你愿意,你可以。
关于微编码的说明,大多数处理器不使用微编码。例如,您可以使用 x86 进入它,因为它在当时是一个很好的指令集,但表面上很难跟上现代的步伐。其他指令集不需要微编码,直接按照我上面描述的方式使用逻辑。您可以将微编码视为使用不同指令集/汇编语言的不同处理器,它模拟您在表面上看到的指令集。不像你在mac上模拟windows或在windows上模拟linux那么复杂。微编码层是专门为这项工作设计的,你可能会认为只有四个寄存器AX、BX、CX、DX,但那里里面还有很多。自然地,一个汇编程序可以在一个或多个内核的多个执行路径上执行。就像闹钟或洗衣机中的处理器一样,微码程序简单而小巧,可以调试并烧录到硬件中,希望永远不需要固件更新。至少理想情况下。但就像您的 ipod 或手机一样,您有时确实需要修复错误或其他任何东西,并且有一种方法可以升级您的处理器(Bios 或其他软件在启动时加载补丁)。假设您打开电视遥控器或计算器的电池盒,您可能会看到一个孔,您可以在其中看到一些裸露的金属触点,可能是三个或五个或更多。对于某些遥控器和计算器,如果您真的想要,您可以重新编程,更新固件。但通常不会,理想情况下,遥控器是完美的或完美到足以比电视机寿命长。微编码提供了在市场上获得非常复杂的产品(数百万、数亿晶体管)并修复该领域中可修复的大错误的能力。想象一下,你的团队在 18 个月内编写了一个 2 亿行的 Python 程序,并且必须交付它,否则公司将无法参加竞赛产品。类似的事情,除了您可以在现场更新的一小部分代码之外,其余部分必须保持不变。对于闹钟或烤面包机,如果有错误或需要帮助的东西,您只需将其扔掉,再换一个。
如果您浏览 wikipedia 或只是 google 资料,您可以查看指令集和机器语言,例如 6502、z80、8080 和其他处理器。可能有 8 个寄存器和 250 条指令,您可以从晶体管的数量中感受到,与每个时钟计算触发器中每个位所需的逻辑门序列相比,这 250 条汇编指令仍然是一种非常高级的语言循环。你的假设是正确的。除了微码处理器,这种低级逻辑不能以任何方式重新编程,您必须用软件修复硬件错误(对于即将交付或将交付但未报废的硬件)。
看看 Petzold 的书,他在解释东西方面做得非常出色,远胜于我所写的任何东西。
【讨论】:
不错的答案。虽然我不会称它为“相对较短”;-)。 @sleske 比较短;相对于讨论该主题可能需要的长度,例如我的答案,它参考了三本教科书和一本实验室手册。与此相比,这个答案很简短。【参考方案3】:我一直在想这件事,并疯狂地在谷歌上搜索。人们会回答“bla bla writes to RAM”之类的问题,但我对“write”的含义很感兴趣。
您总是从输入代码开始,对吧?然后编译,组装,机器代码等......它如何变成晶体管上的电压?可是等等!让我们在这里退一步。当您输入代码时,假设您想用任何语言编写“print 'Hello World'”。在键盘上按下“p”(“print”的第一个字母)的第二次,您实际上是在重新路由由墙壁插座提供的电流,该电流由墙壁插座提供,穿过特定路径到特定的一组晶体管。因此,您实际上已经在此步骤中存储了 0V 和 +5V。不是后期生成的!
这些电压在后续步骤中是如何被冲洗掉的……各个层面的电气科学。
希望这能回答你的问题。
【讨论】:
【参考方案4】:编辑:这是一个 CPU (6502) 的示例,它已在晶体管级别使用 python/javascript 模拟 http://visual6502.org 您可以将您的代码放入其中,看看它是如何做的可以。
编辑:优秀的 10 000m 水平视图:Soul of a New Machine - Tracy Kidder
在我进行微编码之前,我很难想象这一点。然后这一切都说得通了(抽象地)。这是一个复杂的话题,但从一个非常高层次的角度来看。
基本上是这样想的。
cpu 指令本质上是存储在构成内存的电路中的一组电荷。有一些电路会导致这些电荷从内存转移到 CPU 内部。一旦进入 CPU,电荷就会被设置为 CPU 电路布线的输入。这本质上是一个数学函数,会导致更多的电输出发生,并且循环继续。
现代 CPU 要复杂得多,但包含许多层微编码,但原理保持不变。记忆是一组电荷。有移动电荷的电路和其他执行功能的电路将导致其他电荷(输出)馈送到内存或其他电路以执行其他功能。
要了解内存的工作原理,您需要了解逻辑门以及它们是如何由多个晶体管创建的。这导致发现硬件和软件在本质上执行数学意义上的功能是等价的。
【讨论】:
【参考方案5】:非常简短,
机器代码指令作为一系列位存储在处理器中。如果您在处理器数据表中查找MOV
,您会看到它有一个十六进制值,例如(例如)0xA5,这是特定于MOV
指令的......(有不同类型的@987654323 @ 具有不同值的指令,但我们暂时忽略它)。
0xA5 hex == 10100101 binary.
*(这不是 X86 上 MOV
的真正操作码值 - 我只是为说明目的选择一个值)。
在处理器内部,它存储在一个“寄存器”中,它实际上是一个触发器或锁存器的阵列,用于存储电压:
+5
0
+5
0
0
+5
0
+5
这些电压中的每一个都馈入一个门或一组门的输入。
在下一个时钟沿,这些门根据来自寄存器的输入电压更新其输出。
那些门的输出馈送到另一级门,或返回到它们自己。该级别馈入下一个级别,该级别馈入下一个级别,依此类推。
最终,沿线路方式的门输出将连接回另一个锁存器/触发器(内部存储器),或处理器上的一个输出引脚。
Register->(clock)->Gate A->(clock)->Gate B->pin
->latch
(忽略不同门类型和更高级别结构的反馈)
这些操作在一定程度上由核心架构定义并行发生。 “更快”的处理器(例如 2.0GHz 与 1.0GHz)性能更好的原因之一是更快的时钟速度(GHz 值)导致从一组门到下一组门的更快传播。
重要的是要了解,在非常高级别,处理器所做的只是改变引脚电压。我们在使用诸如 PC 之类的设备时看到的所有光荣的复杂性都源自门的内部模式以及连接到处理器的外部设备/外围设备(如其他 CPU、RAM 等)的模式。处理器是其引脚改变电压的模式和序列,以及允许 CPU 某一时刻的状态影响其下一时刻的状态的内部反馈。 (在汇编中,这种状态由标志、指令指针/计数器、寄存器值等表示)
以非常真实的方式,每个操作码(机器代码指令)的位在物理上与处理器的内部结构相关联(尽管在必要时可以通过内部查找表/指令映射在一定程度上抽象出来) .
希望对您有所帮助。我还接受过很好的 EE 教育和大量嵌入式开发经验,所以这些抽象对我来说很有意义,但对新手来说可能不是很有用。
【讨论】:
不错的答案。我一直在寻找的是 MOV 的二进制数字如何转换为电压。我意识到它需要一个硬件(如硬盘磁头)才能“看到”磁盘上的 1 并将寄存器的一部分充电到 2V,然后“看到”0 并将另一个寄存器充电到 0V 等等...... 【参考方案6】:这本书的草稿"Microprocessor Design" is currently online Wikibooks。
我希望有一天它会为这个问题提供一个很好的答案。 同时,也许您仍然可以从当前对该问题的答案草稿中学到一些东西,并帮助我们进行改进或至少指出我们忘记解释的内容以及解释令人困惑的地方。
【讨论】:
【参考方案7】:这个问题需要的不仅仅是 *** 上的答案来解释。
要了解从最基本的电子元件到基本机器代码的所有信息,请阅读The Art of Electronics, by Horowitz and Hill。要了解有关计算机体系结构的更多信息,请阅读Computer Organization and Design by Patterson and Hennessey。如果您想了解更高级的主题,请阅读Computer Architecture: A Quantitative Approach, by Hennessey and Patterson。
顺便说一句,电子艺术也有一个同伴lab manual。如果您有可用的时间和资源,我强烈建议您进行实验室;实际上,我参加了 Tom Hayes 教授的课程,其中我们构建了各种模拟和数字电路,最终用 68k 芯片、一些 RAM、一些 PLD 和一些分立元件构建了一台计算机。您可以使用十六进制键盘将机器代码直接输入 RAM;这是一个爆炸,也是获得计算机最低级别经验的好方法。
【讨论】:
电子艺术摇滚。 可惜最近没更新。它有点过时了。 :-( 否则是一个很好的资源! 我也会推荐SICP后面的章节(mitpress.mit.edu/sicp/full-text/book/book-Z-H-30.html#%_chap_5) @TokenMacGuy 我会建议任何对编程感兴趣的人阅读所有 SICP,但我会说对于这个特殊问题,Horowitz 和 Hill 更适合低级别的亲身体验,而 Patterson Hennessey 更适合描述现实世界中相对现代的计算机体系结构。但是,是的,我总是会推荐阅读 SICP。 讨论寄存器机器的章节帮助我更好地理解逻辑门如何组合成功能块,以及这些块如何组合以执行指令。【参考方案8】:解释此代码并将其作为电压信号发送的处理器内部究竟是什么
我想说“硬件”,但更真实的答案是“microcode”。
【讨论】:
RISC 和 VLIW 架构没有微编码,在嵌入式系统中很普遍。 @CliffordMOV AL, 61h
和 XOR EAX, EBX
是 x86 系列指令。
我仅将其视为典型指令的一般示例;这个问题似乎比这更广泛(也许太广泛了!);但公平一点,这两个例子都是 x86 指令。所以我想知道为什么它被标记为“嵌入式”,因为问题也比这更广泛(而且 x86 在嵌入式系统中并不常见)。【参考方案9】:
一个更简单的介绍,但仍然是一个很好的计算机介绍
Charles' Petzold's code
【讨论】:
【参考方案10】:这是一个非常糟糕的总结:-)
MOV AL, 61h 又是一种人类可读的代码形式,它被输入到汇编器中。汇编器生成等效的十六进制代码,它基本上是处理器可以理解的字节序列,也是您将存储在内存中的内容.在嵌入式系统环境中,链接器脚本可让您细粒度地控制这些字节(程序/数据等的单独区域)在内存中的放置位置。
处理器本质上包含一个使用触发器实现的有限状态机(微代码)。机器从内存中读取(获取周期)“MOV”的十六进制代码,计算出(解码周期)它需要一个操作数,在本例中为 61h,再次从内存中获取它,并执行它(即复制 61进入累加器寄存器。'Read''fetch',execute'等都意味着使用加法器,减法器,多路复用器等数字电路将字节移入和移出移位寄存器
【讨论】:
【参考方案11】:这是一个很大的问题,在大多数大学都有一整个学期的课程来回答这个问题。所以,与其在这个小盒子里给你一些可怕的总结,我会引导你看那本包含全部真相的教科书:Computer Organization and Design: The Hardware/Software Interface by Patterson and Hennessey。
【讨论】:
【参考方案12】:数字电路中最基本的元素应该是Logic Gate。逻辑门可用于构建逻辑电路以执行boolean arithmetic,或解码器,或sequential 电路,例如Flip-Flops。触发器可以被认为是 1 位存储器。它是更复杂的时序电路的基础,例如计数器或寄存器(位阵列)。
microprocessor 只是一堆定序器和寄存器。对微处理器的“指令”只不过是按顺序推入某些寄存器的位模式,以触发特定序列以对“数据”执行计算”。数据表示为位数组......现在我们处于更高的水平。
【讨论】:
以上是关于一条汇编指令如何转化为 CPU 上的电压变化?的主要内容,如果未能解决你的问题,请参考以下文章