我在维基百科上阅读机器码、微码和字节码。
微码似乎比机器码更底层,而字节码似乎更高级。
我并没有真正了解某些东西如何比机器代码更底层,更一般地说,它们都与机器代码相关。
2 回答
有关任何这些术语,请参见 Wikipedia 的网页,在右栏中它说:
源代码是使用人类可读的编程语言编写的任何代码集合,可能带有注释,通常为纯文本。微码将机器指令、状态机数据或其他输入转换为详细的电路级操作序列。它将机器指令与底层电子设备分开,以便可以更自由地设计和更改指令。
“我并没有真正理解某些东西如何比机器码更底层,更一般地说,它们(字节码和微码)如何与机器码相关。”
一个类比是机器代码告诉 CPU 使用哪个微代码(子程序)。
大约半个世纪前,我对英特尔 8080 了如指掌,它对某些人来说是可读的。现代处理器具有更大的指令集,我认为可以公平地说,大多数人,甚至不是某些人,都熟悉他们今天最喜欢的处理器的整个机器代码指令集。
对于特定的处理器架构,机器代码大部分与任何处理器重叠,例如,您可以在 AMD 处理器上运行大多数英特尔优化的机器代码(反之亦然),但每个处理器的微代码不交叉兼容。
有些程序依赖于特定的处理器并且没有挂钩来允许根据所使用的处理器选择不同的子例程,这些程序通常是驱动程序或高度优化的程序,旨在尽快执行(或占用最少内存或其他折衷方案)——这些程序(或驱动程序)通常有多个版本,以适应制造商特定版本的 CPU,这在ARM CPU中尤其常见,其中每个内核支持不同的指令集并且内存有限(所以容纳范围广泛的处理器是不切实际的,并且在嵌入式系统中毫无意义)。
以上是一个易于理解的解释,单击上面的链接可以提供更准确和深入的解释。
在这三种机器代码的上下文中,是处理器运行的指令集,发布的指令以及我们中的一些人学习编程(在汇编语言中,汇编器是将汇编转换为机器代码的工具)。
0: 66 b8 05 00 mov ax,0x5
并非所有处理器都是微编码的,比您想象的要少,几乎没有。它更像是一个顺式的东西而不是一个 RISC 的东西,AFAIK 已经使用了一些 RISC。当您认为微编码时,基本上会想到 x86。
将立即数移入通用寄存器之类的东西似乎不是问题,但是然后看看其他一些允许您拥有内存操作数的指令,例如
0: 66 b8 05 00 mov ax,0x5
4: 66 67 8b 07 mov ax,WORD PTR [bx]
8: 66 67 8b 47 05 mov ax,WORD PTR [bx+0x5]
拿第三个
从寄存器文件中读取 bx 的内容 对该值加 5 使用该地址从内存中执行字大小的加载 将该值保存在寄存器文件中的 ax 中
在简单的加载和存储机器上的一堆步骤将使用更多指令完成,一些伪代码
add r3,r2,#5
load r4,[r3]
mov r1,r4
底层处理器(如果有)可能是字节片或 vliw(非常长的指令字)或为任务创建的东西。
没有理由期待,我们很确定从一代 x86 到另一代,底层微引擎已经发生了变化,也许是完全替代,也许不是。
将其视为 EBCDIC vs ASCII vs unicode 等。基本的字母大写 AZ 小写 az 和 0-9 加上其他一些,我们可以使用不同的编码方案以数字方式表示它们,只有一些人需要知道我们其他人的方案只需在网页上的编辑框中输入这些字符,而不必知道它是如何工作的。
历经多代的处理器可以很容易地重新设计,同时保持与过去的兼容性。如果你让 100 名程序员为一个编程问题写一些详细的描述,你会得到 1 到 100 个不同的解决方案,它们都执行相同的任务。有些人可能比其他人更好。假设所有都没有错误,那么它们都是有效的解决方案。让 100 名 RTL 工程师给他们一个指令集和一个处理器总线规范,你就会得到 1 到 100 种不同的解决方案,其中任何一种在技术上都可以用于实现该处理器。没有理由在几年后使用一种设计之后可能想要使用全新的设计。或者你可以做英特尔的事情,团队 A 构建其他所有处理器,团队 B 构建其他处理器(他们现在可能会也可能不会这样做,但在一段时间内确实如此),因此其他所有可能都基于对先前设计的改进,但下一个可能在下面完全不同。这与微编码与否无关。
你当然可以制作一个没有微编码的 x86,也可以制作一个 MIPS。查找 LC-3 一个非常简单的指令集,可以在大约一页 verilog 中实现,但是大学创建者至少有一个非常庞大的微编码解决方案,用于演示和教育目的。从历史上看和今天一样,构建一个芯片需要大量的工作,每次旋转的成本都很高(想想每次旋转数千万美元),因为旋转越少,你就能卖得越好。如果我想制作一台洗衣机控制器并为了节省大规模生产成本,我希望能在控制器板上的一个芯片中获得尽可能多的东西。我可以选择将其全部设为逻辑,而不是可编程的。但是,如果在芯片投入生产后有任何错误或功能需要更改,那就是芯片旋转,我们会扔掉使用先前芯片构建的电路板。如果我们将其中的一部分设为可编程,而有些则不能添加功能或修复错误,而不必召回或将产品扔到货架上的几率就会下降。有时它的生产成本甚至更低。可编程解决方案不一定总是比非可编程解决方案大,它取决于要解决的问题。该领域的经验指导这些决定。为了获得回报,为这样的产品制造自己的芯片,您必须获得数量上的回报,花费数十万到数百万来生产控制器芯片,这样每个芯片都比用制造电路板便宜几美元微控制器和其他一些芯片。
如上所示,6502、8086 和前代处理器等老一代处理器试图为每条指令执行更多操作。指令集已经发展(或者他们查看 pdp8 并考虑您的问题和 CISC、RISC 等)因此,您可以通过微编码来平衡能够获得可以销售的产品而无需太多芯片旋转但拥有所有这些功能是一个有效的妥协。但随后您开始看到 RISC、VLIW 和其他解决方案,您并没有真正关注用作通用处理器的微引擎,而是关注使用更多指令的设计,但指令更易于实现且执行速度更快。所以有一个设计选择,优点和缺点,正如我们所知,这两种解决方案都能够进行通用计算或专用计算。
转到visual6502页面,看看他们在那里谈论的一些事情。处理器是围绕 rom 设计的,将其视为基于 rom 的状态机,您的操作码本质上是指向 rom 的指针,如果您愿意,rom 包含驱动状态机或微引擎的子命令。也许微码和将机器代码指令分解成更小的步骤是有意义的。AMD 有一个称为 AMD 29000 的处理器,在某种程度上,该处理器成为了第一个/早期 AMD x86 克隆背后的微引擎。Transmeta 采用了另一种方法,即运行时将 x86 代码转换为 VLIW 代码,为什么他们不只是将其作为 VLIW 处理器出售,我不知道......他们的目标是制作 x86 克隆,而不是我猜的一些新处理器......
像 C 这样的语言应该解决在 arpanet 上拥有各种基于处理器的系统能够相互通信的问题。每次在每所大学都必须重新编写通信代码(从头开始编写到规范),以便他们能够交谈。如果您可以制作一种更高级别的语言来实现后端,但高级程序可以在每个目标上运行。虽然由于显而易见的原因 C 仍然非常相关,但 Pascal、Java、Python 和其他人出现了一个更有趣的概念,将高级语言编译成机器代码,但是你可以编写一个特定于目标的机器代码虚拟机为。通常是大多数处理器可以轻松实现的基于堆栈的解决方案,不一定有效,但很有可能成功地为每个目标平台创建虚拟机。如果您不想再随身携带源代码,您可以随身携带字节码。已经编译好了。与指令集模拟器没有太大区别,因此您可以在基于 arm 的手机或基于 x86 的笔记本电脑上的 x86 或 6502 街机游戏(如 Asteroids)上运行 ARM 程序,但字节码指令集在某种程度上是为该模拟器/虚拟机设计的机器,不一定像真正的机器语言那样设计。
例如,完成 JAVA 字节码的方式是您基本上可以为每个字节码指令构建自己的查找表并在本机指令中实现(如果可能,某些指令需要/想要系统调用,您仍然可以在本机代码中执行当然)。再次考虑 6502、8080/z80、8086,您的操作码是一个字节,该字节本身不一定在逻辑上映射为您可以将其分开并查看操作数的方式,它是您用于查找表的字节. 你看看 MIPS、ARM、RISC-V 和其他你真的没有操作码(mips 和 riscv 尝试,但如果你真的看起来不完整),你有一个更大的指令,其中部分指令驱动状态机(更多)直接(理想情况下)。基于操作码的设计操作码被查找或映射到一个表中,该表间接地从操作码/指令的位驱动状态机。是的,这些 RISC 有一些操作码位之间有些模糊,CISC 可能有一些可以更直接使用的位。
我们看到的字节码的另一个用途是像 LLVM 这样的即时编译器。开始并仍然使用它作为其主干,编译器前端创建字节码,然后可以在该级别优化字节码,然后最终及时或在构建项目时编译字节码,如果您愿意进入目标汇编语言或机器代码。字节码是所有可能的前端语言和所有实现的后端目标之间的一个很好的中间抽象层。
与我概括的 RISC 与 CISC 比较一样,您当然可以将 JAVA 编译为目标代码,同样您可以制作一个 C 编译器/工具链,为这些虚拟机之一输出字节码。
机器代码,处理器在运行什么,他们理解什么,告诉他们做某事的指令。
微码,一些处理器设计通过使用另一个理想上更简单的指令集基本上模拟机器代码指令来实现机器代码。在微引擎上运行的微代码。
字节码,一种理想的通用指令集,可以在虚拟机中进行仿真,以便可以在不兼容的系统上交付和使用已编译的程序。只需为 VM 开发一次程序并交付它,相同的二进制文件。不必为每个目标操作系统/指令集开发一个版本。该术语还用作从工具链中可能的目标后端抽象编译语言前端的一种方式。