assembly指令如何变成CPU上的电压变化?
在过去的3 – 5年里,我一直在C和CPython工作。 考虑一下我的知识基础。
如果我将一个汇编指令(如MOV AL, 61h
用于支持它的处理器,那么处理器内部究竟是什么内容来解释这个代码并将其作为电压信号进行调度? 这样一个简单的指令怎么可能被执行呢?
当我试图想到MOV AL, 61h
甚至XOR EAX, EBX
包含的大量步骤时,Assembly甚至感觉像是高级语言。
编辑:我读了一些评论,问为什么我把这个作为embedded式时,x86系列是不常见的embedded式系统。 欢迎来到我自己的无知。 现在我认为,如果我对此一无所知,也可能有其他人对此毫无所知。
考虑到你们所有人的努力,对于我来说,select一个最喜欢的答案是困难的,但是我感到不得不作出决定。 没有伤害的感觉,家伙。
我经常发现,我对计算机了解得越多,我越是意识到自己真的知道了。 感谢您打开我的想法微码和晶体pipe逻辑!
编辑#2:感谢这个线程,我只是理解为什么XOR EAX, EAX
比MOV EAX, 0h
更快。 🙂
我最近开始阅读Charles Petzold的一本名为“Code”的书,它到目前为止涵盖了我假设你很好奇的一些事情。 但是,在购买/借阅之前,我还没有完全通过这本书。
这是我比较简短的答案,不是Petzolds …希望符合你的好奇心。
你听说过我设想的晶体pipe。 使用晶体pipe的原始方式就像晶体pipe收音机。 它基本上是一个放大器,将微小的无线电信号悬浮在空气中,并将其馈送到晶体pipe的input端,从而打开或closures旁边电路的电stream。 而且你用更高的功率连接电路,所以你可以采取一个非常小的信号,放大它,并将其馈入扬声器,例如收听广播电台(隔离频率和保持晶体pipe平衡,但更多的是,但你得到了我希望的想法)。
现在晶体pipe的存在导致了一种使用晶体pipe作为开关的方式,就像一个灯开关。 收音机就像一个调光灯开关,你可以把它从任何地方转到任何地方。 一个非调光的灯开关全部或全部closures,在开关的中间有一些魔术地方,它会改变。 我们在数字电子学中使用晶体pipe。 取出一个晶体pipe的输出,并将其馈入另一个晶体pipeinput。 第一个的输出肯定不是像无线电波那样的小信号,它迫使第二个晶体pipe一直通电或一直通电。 这导致了TTL或晶体pipe – 晶体pipe逻辑的概念。 基本上你有一个驱动高电压的晶体pipe,或者把它叫做1,然后在其上吸一个零电压,让它叫0。然后你用其他电子设备来安排input,这样你就可以创buildAND门(如果两个input是1则输出是1),或门(如果其中一个或另一个input是1,那么输出是一个)。 反相器,NAND,门,NOR门(一个或一个反相器)等曾经是一个TTL手册,你可以买8个左右的引脚芯片有一个或两个或四个某种types的门(NAND,NOR, AND等)内部有两个input和一个输出。 现在我们不需要那些用数百万个晶体pipe来创build可编程逻辑或专用芯片的便宜。 但是我们仍然用AND,OR,而不是硬件devise的大门来思考。 (通常更像是nand也不)。
我不知道他们现在教什么,但概念是一样的,对于内存来说,一个触发器可以被认为是两个TTL对(NANDS)绑在一起,一个输出到另一个input。 让我们离开它。 这基本上是我们所说的SRAM或静态RAM中的一个单一位。 sram基本上需要4个晶体pipe。 你自己装在电脑里的记忆棒或者dynamic内存棒,你自己就可以拿到一个晶体pipe,所以对于初学者来说,你可以看到为什么你需要购买千兆字节的数据。 只要权力没有消失,斯拉姆就会记住你设定的东西。 Dram开始忘记你告诉它之后告诉它的内容,基本上dram使用的晶体pipe有三种不同的方式,有一些电容(如电容器,不会进入这里),就像一个微小的可充电电池,一旦你充电,拔下充电器开始排水。 想想每个玻璃杯上都有一排小孔的架子上的一排眼镜,这些都是你的眼镜,你想让它们中的一些成为眼镜,所以你有一个助手可以填满你想成为一个眼镜的眼镜。 助手必须不断地填满投手,然后下车,并保持“一”位杯足够水,让“零”位眼镜保持空置。 所以在任何时候你想看看你的数据是什么,你可以通过查找水位绝对高于一个中间水平,并确定中间低于零水平读取零和零。如果助手不能够保持足够的眼镜从零告诉一个人,他们最终会看起来像零和排水。 它的每芯片更换位的权衡。 所以这里的短小故事是,在处理器之外,我们使用dram来处理大容量的内存,并且有一个助理逻辑来保持这个逻辑的零和一个零。 但是在芯片内部,AX寄存器和DS寄存器例如使用触发器或sram保持数据。 对于你所知道的每一个比特,比如AX寄存器中的位,有可能有数百或数千甚至更多的数据被用来从AX寄存器中获取数据。
你知道处理器以一些时钟速度运行,这些日子大概是2千兆赫或者是每秒钟20亿个时钟。 考虑一个由水晶产生的时钟,另一个话题,但是逻辑把时钟看作一个电压,在这个时钟频率2ghz或者其他什么的情况下,这个时钟是高电平和零电压(游戏机的进步是17mhz,旧的ipod在75mhz左右,原装ibm pc 4.77mhz)。
所以用作开关的晶体pipe可以让我们把电压转换成硬件工程师和软件工程师所熟悉的那些零和零,甚至可以给我们AND,OR和NOT的逻辑function。 而且我们有这些神奇的晶体让我们得到精确的电压振荡。
所以我们现在可以做一些事情,比如说,如果时钟是一个,而我的状态variables表示我处于取指令状态,那么我需要切换一些门,使得我想要的指令的地址在程序计数器,在内存总线上出去,所以内存逻辑可以给我指令MOV AL,61h。 您可以在x86手册中查看这些内容,发现其中一些操作码位表示这是一个mov操作,目标是EAX寄存器的低8位,mov的源是一个立即值,意味着它在这个指令之后是在内存位置。 所以我们需要在某个地方保存指令/操作码,并在下一个时钟周期中取出下一个存储单元。 所以现在我们已经保存了mov al,立即从内存中读取值61h,并且我们可以切换一些晶体pipe逻辑,使得那个61h的第0位存储在al的第0位触发器和第1位到第1位等。
你发生的一切如何? 想想一个执行一些math公式的python函数。 你从程序的顶部开始,input一些公式作为variables来input,你可以在程序中单独执行一些步骤,在这里可以添加一个常量,或者从库中调用平方根等函数。在底部,返回答案。 硬件逻辑是以同样的方式完成的,今天使用的编程语言之一看起来很像C语言。主要的区别在于你的硬件function可能有成百上千的input,输出是一个单一的位。 在每个时钟周期,AL寄存器的第0位正在用一个巨大的algorithm来计算,取决于你想要看多远。 考虑一下你为math运算调用的平方根函数,该函数本身就是其中的一个input,产生一个输出,它可能调用其他函数,可能是乘法或除法。 所以在AL寄存器的第0位之前的最后一步,你可能会想到它的某个地方,它的function是:如果时钟是1,那么AL [0] = AL_next [0]; 否则AL [0] = AL [0]; 但是有一个更高级的函数,包含从其他input计算出来的下一个比特,一个更高的函数和更高的函数,其中大部分是由编译器创build的,就像你的三行python可以变成数百或数千汇编程序的线。 几行HDL可以变成数百或数千或更多的晶体pipe。 硬件人员通常不会查看特定位的最低级别公式,以找出所有可能的input以及所有可能的AND和OR以及计算所需的NOT数量,而不是您可能检查程序生成的汇编程序。 但你可以,如果你想。
关于微码的一个说明,大多数处理器不使用微码。 例如,你可以用x86进入它,因为它是一个精美的指令集,但表面上却与现代化保持一致。 其他的指令集不需要微编码,直接按照上面描述的方式使用逻辑。 您可以将微代码视为不同的处理器,使用不同的指令集/汇编语言来模拟您在表面上看到的指令集。 不像当你试图模拟Windows上的Mac或Linux上的Windows时那么复杂。微码层是专门为这项工作devise的,你可能会想到只有四个寄存器AX,BX,CX,DX,但是在那里更多的内部。 自然,一个汇编程序可以在一个核心或多个核心的多个执行path上执行。 就像闹钟或洗衣机中的处理器一样,微码程序也很简单,很小,debugging和烧录到硬件中,希望不需要固件更新。 至less在理想情况下。 但像你的iPod或手机,例如你有时确实想要一个错误修复或其他任何方式,并有一种方法来升级你的处理器(BIOS或其他软件加载补丁启动)。 假设你打开电视机的遥控器或计算器,你可能会看到一个洞,你可以看到一排裸露的金属触点,可能是三个,五个或多个。 对于一些遥控器和计算器,如果你真的想要你可以重新编程它,更新固件。 通常情况下,尽pipe如此,理想情况下,遥控器是完美的或完美的,足以胜过电视机。 微码提供了在市场上获得非常复杂的产品(数以百万计,数以亿计的晶体pipe)的能力,并且解决了大量的和可修复的问题。 想象一下,你们团队在18个月内写下了2亿行python程序,必须交付,否则公司将无法参与竞争产品。 除了只有一小部分代码可以在现场更新外,其余部分都是一成不变的。 对于闹钟或烤面包机,如果有一个错误或者需要帮助的东西,就把它扔出去,换另一个。
如果你通过维基百科或谷歌的东西挖掘,你可以看看6502,Z80,8080和其他处理器的指令集和机器语言。 可能有8个寄存器和250个指令,你可以从晶体pipe的数量中得知,250个汇编指令仍然是一个非常高级的语言,与每个时钟在一个触发器中计算每个位所需的逻辑门序列周期。 你的假设是正确的。 除了微码处理器之外,这种低级逻辑不能以任何方式进行重新编程,您必须用软件修复硬件错误(对于正在交付或即将交付的硬件)。
看看Petzold的书,他在解释东西方面做得非常出色,远远超过我所能写的东西。
编辑:这是一个CPU(6502)的例子,已被模拟使用python / JavaScript在TRANSISTOR LEVEL http://visual6502.org你可以把你的代码看看它是如何做到这一点。
编辑:优秀10 000m等级视图: 新机器的灵魂 – Tracy Kidder
直到我做了微代码之前,我很难想象这一点。 那么这一切都是有道理的(抽象的)。 这是一个非常复杂的话题,但是处于非常高的层次。
基本上是这样想的。
cpu指令本质上是存储在构成存储器的电路中的一组费用。 有电路会导致这些费用从内存转移到CPU的内部。 一旦进入CPU,电荷被设置为CPU电路接线的input。 这本质上是一个math函数,会导致更多的电力输出发生,并且循环继续。
现代的cpus远远更复杂,但包括许多层次的微代码,但原理保持不变。 记忆是一套收费。 有电路移动电荷和其他电路执行function将会导致其他的充电(输出)馈送到存储器或其他电路来执行其他function。
要理解内存如何工作,您需要了解逻辑门以及如何从多个晶体pipe创build它们。 这导致发现硬件和软件在math意义上基本上执行function的意义上是等价的。
这是一个需要在StackOverflow上进行解释的问题。
要从最基本的电子元件到基本的机器代码,了解这一点,请阅读Horowitz和Hill的“电子艺术” 。 要了解更多关于计算机体系结构的信息,请阅读Patterson和Hennessey的Computer Organization and Design 。 如果您想进入更高级的话题,请阅读Hennessey和Patterson撰写的“Computer Architecture:A Quantitative Approach” 。
顺便说一下,电子艺术也有一个伴侣实验手册 。 如果您有足够的时间和资源,我会强烈build议您做实验室; 我实际上参加了由汤姆·海耶斯(Tom Hayes)教授的课程,其中我们构build了各种模拟和数字电路,最终用68k芯片,一些RAM,一些PLD和一些分立元件构build了一台计算机。 您可以使用hex键盘直接将机器代码input到RAM中; 这是一个爆炸,也是一个很好的方式,在最低级别的电脑上获得经验。
如果没有整本书,详细地解释整个系统是不可能的,但这里是一个简单的计算机的高层次的概述:
- 在最底层有物理和材料(例如由掺杂硅制成的晶体pipe)。
- 使用物理和材料,你可以导出NAND逻辑门 。
- 使用与非门,你可以得到所有其他的基本逻辑门(AND,OR,XOR,NOT等),或者为了从晶体pipe直接构build它们,包括具有多于2个input的版本。
- 使用基本的逻辑门,可以导出更复杂的电路,如加法器 , 多路复用 器等等。
- 同样使用基本的逻辑门,你可以派生出有状态的数字电路元件,如触发器 , 时钟等等。
- 使用更复杂的状态电路,你可以派生更高层次的部分,如计数器 , 存储器 , 寄存器 , 算术逻辑单元等。
- 现在你只需要把你的高级作品拼在一起,
- 价值来自内存
- 该值被解释为一个指令,通过使用多路复用器等将其分配到适当的位置(例如,ALU或存储器)(基本指令types是从存储器读入到寄存器,从寄存器写入到存储器,内存,执行寄存器操作和跳转指令)。
- 该过程重复下一条指令
要理解assembly指令如何引起电压变化,您只需要了解每个级别如何由下面的级别表示。 例如,一条ADD指令将使两个寄存器的值传播给ALU,ALU具有计算所有逻辑操作的电路。 然后在另一侧的多路复用器被送入来自指令的ADD信号,select期望的结果,该结果传播回到其中一个寄存器。
这是一个很大的问题,而且大多数大学都有整整一个学期的课程来回答。 所以,而不是在这个小方块里给你一些非常凶狠的总结,而是引导你阅读具有全部真理的教科书: 计算机组织和devise:Patterson和Hennessey的硬件/软件接口 。
一个简单的介绍,但仍然非常好介绍从电线计算机
Charles的Petzold的代码
很简单,
机器代码指令作为一系列位存储在处理器内。 如果在处理器数据表中查找MOV
,则会看到它具有一个hex值,例如0xA5,这对于MOV
指令是特定的。(有不同types的MOV
指令,其值不同,但暂时忽略这一点)。
0xA5 hex == 10100101 binary.
*(这不是X86上MOV
的真正操作码值 – 我只是为了说明而select一个值)。
在处理器内部,它被存储在一个“寄存器”中,这个寄存器实际上是一系列触发器或锁存器,可以存储一个电压:
+5
0
+5
0
0
+5
0
+5
这些电压中的每一个都馈入一个门或一组门的input端。
在下一个时钟沿,这些门将根据寄存器的input电压更新其输出。
这些门的输出进入另一层门,或回到自己的门。 这个级别进入下一个,进入下一个,等等。
最终,线路上的门极输出将连接回另一个锁存器/触发器(内部存储器)或处理器上的一个输出引脚。
Register->(clock)->Gate A->(clock)->Gate B->pin ->latch
(忽略对不同门types和更高级别结构的反馈)
这些操作在核心架构定义的一定程度上并行发生。 “更快”的处理器(2.0GHz和1.0GHz)performance更好的原因之一是更快的时钟速度(GHz值)导致从一个门集合到另一个门的传播更快。
理解这一点非常重要,在很高的层面上,处理器所做的就是改变引脚电压。 我们在使用像PC这样的设备时所看到的所有光荣的复杂性都来源于门的内部模式和连接到处理器的外部设备/外围设备中的模式,如其他CPU,RAM等。处理器是其引脚改变电压的模式和顺序,内部反馈允许CPU一次的状态在下一个时刻对其状态做出贡献。 (在汇编中,这个状态由标志,指令指针/计数器,寄存器值等表示)
以非常实际的方式,每个操作码(机器码指令)的位在物理上与处理器的内部结构相关联(尽pipe在必要的情况下,可以通过内部查找表/指令映射将其抽象到一定程度)。
希望有所帮助。 我也有很好的EE教育背景和丰富的embedded式开发经验,所以这些抽象对我来说是有意义的,但对新手来说可能不是很有用。
数字电路中最基本的元件应该是逻辑门 。 逻辑门可以用来构build逻辑电路来执行布尔运算 ,或者解码器,或者诸如触发器的 顺序电路。 触发器可以被认为是1位的存储器。 它是更复杂的时序电路的基础,例如计数器或寄存器(位数组)。
微处理器只是一串序列器和寄存器,对微处理器的“指令”只不过是顺序地压入某些寄存器的位模式,以触发特定的序列来执行“数据”上的计算。 数据被表示为位数组……现在我们处于更高层次。
“微处理器devise”一书的草稿目前在Wikibooks上线。
我希望有一天它会对这个问题作出很好的回答。 同时,也许你仍然可以从目前这个问题的答案中学到一些东西,帮助我们改进,或者至less指出我们忘记解释的东西以及解释混乱的地方。
那么这里是一个非常屠杀的总结:-)
MOV AL,61h也是一种人类可读的代码forms,汇入汇编器。汇编器产生等价的hex代码,基本上是处理器可以理解的一系列字节,而且是存储在内存中的。在embedded式系统环境中,链接器脚本为您提供精细的控制,以便将这些字节(程序/数据等的独立区域)放在内存中。
处理器本质上包含使用触发器实现的有限状态机(微码)。 机器从存储器中读取(取回周期)'hex'的hex代码,计算出(解码周期)它需要一个操作数,在这种情况下是61h,再次从存储器中取出并执行它(即复制61进入累加器寄存器。“读取”,“执行”等全部意味着使用加法器,减法器,复用器等数字电路将字节移入/移出移位寄存器
处理器内部究竟是什么内容来解释这个代码并将其作为电压信号进行调度
我想说'硬件',但更真实的答案是' 微码 '。
我一直在想这个,疯狂地Googlesearch。 人们回答“bla bla bla to RAM”这样的东西,但是我真的对这个“写”的含义感兴趣。
你总是开始input代码,对吧? 然后得到编译,汇编,机器代码等等……它是如何变成晶体pipe上的电压的? 可是等等! 让我们回到这里。 当你input代码时,假设你想用任何语言编写“print'Hello World'”。 第二个按下键盘上的“p”(“打印”的第一个字母),实际上是将墙壁sockets提供的电stream跨越一定path重新路由到某一组晶体pipe。 所以你在这一步实际上已经存储了0V和+ 5V。 它不会在以后生成!
在后面的步骤中如何刷新这些电压是很好的…各级电气科学。
希望这回答你的问题。