汇编指令如何转化为CPU上的电压变化?

2024-01-12

过去 3 - 5 年我一直从事 C 和 CPython 工作。考虑一下我的知识基础。

如果我要使用汇编指令,例如MOV AL, 61h对于支持它的处理器,解释该代码并将其作为电压信号调度的处理器内部到底是什么?如此简单的指令如何执行?

当我尝试思考其中包含的众多步骤时,汇编甚至感觉像是一种高级语言MOV AL, 61h甚至XOR EAX, EBX.

编辑:我读到一些评论,询问为什么我将其作为嵌入式,而 x86 系列在嵌入式系统中并不常见。欢迎承认我自己的无知。现在我想,如果我对此一无所知,那么很可能其他人也对此一无所知。

考虑到你们为答案付出的努力,我很难选择一个最喜欢的答案,但我觉得有必要做出决定。没有受伤的感觉,伙计们。

我经常发现,我对计算机了解得越多,我意识到自己真正了解的就越少。感谢您让我对微代码和晶体管逻辑敞开心扉!

编辑#2:感谢这个线程,我刚刚理解了为什么XOR EAX, EAXMOV EAX, 0h. :)


我最近开始阅读 Charles Petzold 的书《Code》,到目前为止,这本书完全涵盖了我认为您感兴趣的内容。但我还没有完全读完,所以在购买/借阅之前先浏览一下这本书。

这是我相对简短的答案,不是 Petzolds……希望符合您的好奇心。

我想你听说过晶体管。使用晶体管的最初方法是用于晶体管收音机之类的东西。它基本上是一个放大器,将漂浮在空气中的微小无线电信号馈送到晶体管的输入端,晶体管打开或关闭旁边电路上的电流。你用更高的功率连接该电路,这样你就可以获取一个非常小的信号,放大它并将其馈送到扬声器中,例如收听广播电台(还有更多隔离频率和保持晶体管平衡的功能,但是我希望你能明白)。

现在晶体管的存在导致了一种使用晶体管作为开关的方法,就像电灯开关一样。收音机就像一个调光开关,您可以将其切换到任何位置,从一直开到一直关。非调光灯开关要么全部打开,要么全部关闭,开关中间有一个神奇的地方可以切换。我们在数字电子产品中以同样的方式使用晶体管。获取一个晶体管的输出并将其馈送到另一个晶体管的输入。第一个晶体管的输出当然不是像无线电波那样的小信号,它迫使第二个晶体管一直打开或一直关闭。这就引出了 TTL 或晶体管-晶体管逻辑的概念。基本上你有一个晶体管驱动高电压或者我们称之为 1,然后它吸收零电压,我们称之为 0。然后你将输入与其他电子设备一起排列,这样你就可以创建与门(如果两个输入是 1,则输出是 1),或门(如果一个或另一个输入是 1,则输出是 1)。反相器、NAND、门、或非门(一个或一个反相器)等。曾经有一本 TTL 手册,你可以购买 8 个左右引脚的芯片,其中有一个或两个或四个某种门(NAND、NOR、 AND 等)内部函数,每个有两个输入和一个输出。现在我们不需要这些,创建具有数百万个晶体管的可编程逻辑或专用芯片会更便宜。但我们仍然从硬件设计的“与”、“或”和“非”门的角度来思考。 (通常更像nand 和nor)。

我不知道他们现在教什么,但概念是相同的,对于内存来说,触发器可以被认为是两个这样的 TTL 对 (NAND),其中一个的输出连接到另一个的输入。让我们就这样吧。这基本上是我们所说的 SRAM 或静态 RAM 中的一个位。 sram 基本上需要 4 个晶体管。 DRAM 或动态 RAM(您自己放入计算机中的记忆棒,每一位都占用一个晶体管),因此对于初学者来说,您可以明白为什么 DRAM 是您购买的价值千兆字节的东西。只要电源不中断,Sram 位就会记住您的设置。一旦你告诉它,Dram 就开始忘记你告诉它的内容,基本上 dram 以第三种不同的方式使用晶体管,有一些电容(如电容器,这里不会讨论)就像一个微型可充电电池,一旦你给它充电并拔掉充电器,它就开始耗尽。想象一下架子上有一排玻璃杯,每个玻璃杯上都有小孔,这些是你的碎片,你想要其中一些是那些,所以你有一个助手来填充你想要成为的玻璃杯。那个助手必须不断地把水罐装满,然后沿着一排走下去,让“一”位的玻璃杯装满水,让“零”位的玻璃杯保持空状态。因此,任何时候您想查看数据是什么,您都可以通过查找绝对高于中间值的水位为 1 以及绝对低于中间值的水位为 0 来查看并读取 1 和 0。打开电源后,如果助手无法将眼镜保持足够满以区分一和零,它们最终都会看起来像零并耗尽。这是每个芯片更多位数的权衡。这里的简短故事是,在处理器之外,我们使用 DRAM 作为大容量内存,并且有辅助逻辑负责保持 1 和 0 为 0。但在芯片内部,AX 寄存器和 DS 寄存器等使用触发器或 sram 保存数据。对于您所了解的每一位(例如 AX 寄存器中的位),可能有数百、数千或更多位用于将这些位移入或移出该 AX 寄存器。

您知道处理器以一定的时钟速度运行,目前约为 2 GHz 或每秒 20 亿个时钟。想想时钟,它是由晶体产生的,另一个话题,但逻辑将时钟视为一个电压,在这个时钟速率 2ghz 或任何其他频率下变高、变高、变为零(gameboy advance 为 17mhz,旧 ipod 约为 75mhz,原装 IBM 电脑 4.77mhz)。

因此,用作开关的晶体管使我们能够获取电压并将其转换为我们作为硬件工程师和软件工程师所熟悉的 1 和 0,甚至为我们提供 AND、OR 和 NOT 逻辑功能。我们拥有这些魔法晶体,可以让我们获得准确的电压振荡。

所以我们现在可以做这样的事情,如果时钟是 1,并且我的状态变量表示我处于获取指令状态,那么我需要切换一些门,以便我想要的指令的地址位于程序计数器,在内存总线上输出,以便内存逻辑可以给我 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];但是有一个更高的函数包含从其他输入计算出的下一个位,还有一个更高的函数和一个更高的函数,其中大部分是由编译器创建的,就像你的三行Python可以变成数百或数千行一样汇编程序行。几行 HDL 可以变成数百、数千或更多的晶体管。硬件人员通常不会查看特定位的最低级公式来找出所有可能的输入以及所有可能的 AND、OR 和 NOT,而这些计算所需的时间可能比检查程序生成的汇编器要多。但如果你愿意的话你可以。

关于微编码的注释,大多数处理器不使用微编码。例如,你会喜欢 x86,因为它在当时是一套很好的指令集,但表面上很难跟上现代的步伐。其他指令集不需要微编码,直接按照我上面描述的方式使用逻辑。您可以将微编码视为使用不同指令集/汇编语言的不同处理器,该处理器模拟您在表面上看到的指令集。不像你尝试在 mac 上模拟 windows 或在 windows 上模拟 linux 等那么复杂。微编码层是专门为这项工作而设计的,你可能会认为只有 AX、BX、CX、DX 这四个寄存器,但是有里面还有很多。当然,一个汇编程序可以以某种方式在一个核心或多个核心的多个执行路径上执行。就像闹钟或洗衣机中的处理器一样,微代码程序简单而小,经过调试并烧录到硬件中,希望永远不需要固件更新。至少理想情况下是这样。但就像你的 iPod 或手机一样,你有时确实需要错误修复或其他什么,并且有一种方法可以升级你的处理器(BIOS 或其他软件在启动时加载补丁)。假设您打开电视遥控器或计算器的电池盒,您可能会看到一个孔,您可以在其中看到一些连续的裸露金属触点,可能是三个、五个或多个。对于某些遥控器和计算器,如果您确实愿意,可以重新编程,更新固件。但通常情况下不会,理想情况下遥控器是完美的或完美到足以比电视机更耐用。微编码提供了将非常复杂的产品(数百万、数亿个晶体管)推向市场并修复该领域中重大且可修复的错误的能力。想象一下,您的团队在 18 个月内编写了一个 2 亿行的 Python 程序,并且必须交付它,否则公司将无法提供竞争产品。同样的事情,除了你可以在现场更新的一小部分代码之外,其余的都必须保留在石头上。对于闹钟或烤面包机,如果有错误或需要帮助,您只需将其扔掉并重新购买即可。

如果您深入维基百科或谷歌搜索,您可以查看 6502、z80、8080 和其他处理器等的指令集和机器语言。可能有 8 个寄存器和 250 条指令,您可以从晶体管的数量中感受到,与每个时钟计算触发器中每个位所需的逻辑门序列相比,250 条汇编指令仍然是一种非常高级的语言循环。你的这个假设是正确的。除了微编码处理器之外,这种低级逻辑不能以任何方式重新编程,您必须使用软件修复硬件错误(对于已交付或将要交付且未报废的硬件)。

查一下佩措尔德的书,他在解释方面做得非常出色,远远优于我写的任何东西。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

汇编指令如何转化为CPU上的电压变化? 的相关文章

  • 如何在 GCC C++ 中编写多行内联汇编代码?

    这看起来不太友好 asm command 1 command 2 command 3 我真的必须在每一行加上双引号吗 另外 由于多行字符串文字在 GCC 中不起作用 我也无法欺骗它 我总是在互联网上找到一些例子 该人手动插入制表符和换行符而
  • Windows CE 与嵌入式 Linux [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 现在我确信我们都清楚 Linux 与 Windows 桌面的相对优点 然而 我对嵌入式开发世界的了解却少得多 我主要对行业解决方案感兴
  • 标志寄存器中保留/未定义位的用途是什么?

    在 Z80 8080 8085 和 8086 处理器的标志寄存器中 被记录为 保留 或 未定义 的位 1 3 5 的用途是什么 这些位未使用 也就是说 没有指令明确地将它们设置为任何值 设计人员认为 5 6 个标志就足够了 他们只是将标志寄
  • ARM Cortex-M3 启动代码

    我试图了解 STM32 微控制器的 Keil realview v4 附带的初始化代码是如何工作的 具体来说 我试图了解堆栈是如何初始化的 In the 文档 http infocenter arm com help index jsp t
  • 从 DX:AX 寄存器转移到单个 32 位寄存器

    我在添加 16 位乘法的乘积时遇到问题 我想将一年 例如 2015 年 乘以 365 为此 我 mov dx 0 to clear the register mov ax cx cx holds the year such as 2015
  • 难以理解汇编命令“加载有效地址”[重复]

    这个问题在这里已经有答案了 可能的重复 LEA 指令的目的是什么 https stackoverflow com questions 1658294 whats the purpose of the lea instruction LEA指
  • 比“add esp, 4”更小的指令

    又是我 我的程序中有很多 add esp 4 我正在尝试减小它的大小 是否有任何更小的指令可以替代 add esp 4 pop edx 或者您不介意破坏的任何其他整数寄存器 这就是现代编译器实际上所做的 https stackoverflo
  • 使用 ACPI 在 MS-DOS 中关闭计算机

    我在基于 Pentium 的计算机上运行 MS DOS 6 22 主板支持 ACPI 并且想知道是否有一个可以用来关闭计算机的汇编语言例程 或者它是否比那个更难 即主板 具体的 基本上 我想创建一个小程序来从命令行关闭计算机 这是专门为此编
  • 为什么 LED 保持亮起而不是闪烁?

    这是使用 pic16f676 中的 TIMER0 中断使 LED 闪烁的 MPASM 代码 端口 A 的引脚 0 RA0 未切换至关闭位置 请帮忙 我是图片组装的新手 我想掌握图片 有没有高手帮我学习一下 我需要以 1 秒的间隔眨眼 代码是
  • movsbl指令的作用是什么? [复制]

    这个问题在这里已经有答案了 我在网上搜索过 但找不到明确的示例来理解该指令的作用 因此 如果有人可以举一个例子 这对我来说将会非常有帮助 用符号从字节扩展到长字移动 在Intel语法中 该指令的助记符是MOVSX 当变量类型为 C 时 C
  • 如何从程序内部获取指向程序的特定可执行文件部分的指针? (也许是诽谤)

    我在 Linux 环境中 需要编写一个程序来检索放置在其可执行文件的某个部分中的一些数据 那么 如何从程序内部获取指向程序某个部分 通过其名称 的指针呢 我知道可以使用elf getdata 将节的索引作为参数传递给 get 和Elf Da
  • NASM:如何正确访问SSD驱动器?

    我需要使用 NASM 16 位代码访问 SSD 驱动器 访问普通硬盘时 需要设置寄存器AX DX CX来选择柱面 磁道 扇区 扇区数 AH 选择读扇区功能 DL 选择驱动器号 CH 选择气缸 DH 选择磁盘上的一侧 CL 选择步入正轨的部门
  • 如何使 gcc 为 -fpatchable-function-entry 发出多字节 NOP?

    gcc确实有能力使用多字节用于对齐循环和函数的 NOP 然而当我尝试 fpatchable function entry option https gcc gnu org onlinedocs gcc Instrumentation Opt
  • 在共享库中不使用 PLT 的情况下调用另一个目标文件中的函数?

    我有两个汇编代码 code1 s and code2 s我想从这两个构建一个可重定位 使用 fPIC 开关 共享库 I want code2 s调用一个函数 名为myfun1 其定义在code1 s 当我使用call myfun1 PLT
  • 微软怎么能说WinAPI中一个字的大小是16位呢?

    我刚刚开始学习WinAPI 在MSDN中 对WORD数据类型提供了以下解释 WORD16 位无符号整数 范围是十进制 0 到 65535 该类型在 WinDef h 中声明如下 typedef 无符号短 WORD 很简单 而且它与我一直在使
  • 为什么这个函数在额外读取内存时运行速度如此之快?

    我目前正在尝试了解 x86 64 上某些循环的性能属性 特别是我的 Intel R Core TM i3 8145U CPU 2 10GHz 处理器 具体来说 在循环体内添加一条额外的指令来读取内存几乎可以使性能提高一倍 而细节并不是特别重
  • 内联汇编跳转后抛出 C++ 异常

    我有一些奇怪的自修改代码 但其根源是一个非常简单的问题 我希望能够执行jmp or a call 然后从该任意点抛出一个异常并让包含该异常的 try catch 块捕获该异常jmp call 但是当我这样做时 在 gcc 4 4 1 x86
  • 英特尔 JCC 勘误表 - 用于缓解的前缀有什么影响?

    Intel 推荐 https www intel com content dam support us en documents processors mitigations jump conditional code erratum pd
  • /usr/bin/as:无法识别的选项“-EL”

    因此 在为我的1plus手机编译android内核时 经过3天的多次尝试 我放弃了并尝试在这里询问是否有人以前遇到过这个问题 这个错误对我来说有点模糊 但我觉得问题来自于我最近对 GNU Linux 发行版 Gentoo 的更改 它在不应该
  • 是否“static/extern uint8_t array[2] = {0};”符合ANSI C规范吗?

    我对以下代码有疑问 include all needed h static uint8 t array 2 0 void main void 是否允许按上述方式初始化 模块 全局数组 以便在符合 ANSI C 的情况下将每个成员设置为零 我

随机推荐