【问题标题】:How do computers set a register to a constant value?计算机如何将寄存器设置为常数值?
【发布时间】:2013-08-05 08:23:26
【问题描述】:

警告 1:我对现实生活中的实用 CPU 设计一无所知。

警告 2: 我不知道“CPU 指令”、“CPU 操作”和“CPU 功能”等术语之间的区别。也许有一个,也许没有,但我把它们当作同义词一样使用。如果我错了,请纠正我。

背景:假设您有一个带有两个寄存器的 4 位 CPU。现在您需要加载一个常量值到寄存器 1!可能有几种方法可以做到这一点:

  • 类似 0SXX 的指令,其中 0 表示它是“将寄存器设置为 X”类型的指令,而 S 表示应该将 XX 加载到寄存器 1 的哪一侧。
    • 优点:寄存器 1 易于操作。仅使用两个字节的程序存储器即可设置一个常数值。
    • 缺点:消耗一半可能的 CPU 指令。对于我的 4 位小设备来说,这是一个悲剧,但对于 >=8 位计算机来说,这可能不是什么大问题。
  • 纯算术/按位系列 CPU 函数(如 AND、OR、NOT、XOR、RoR、RoL、INC 等...)
    • 优点:无需额外的 CPU 实现。
    • 缺点:需要更多指令,常量加载速度较慢,当然,在汇编中加载常量之前需要考虑更多。
  • 介于两者之间吗?比如清空寄存器,加载??XX,然后逻辑运算?
  • 还有什么我没想到的?

一般情况:

  • 有没有一种方法可以让所有普通的现代 CPU 将寄存器设置为常数值?
    • 如果不是,最常用的方法是什么?
  • 旧的 4/8 位计算机是否有不同的方法来做到这一点?

我认为任何接触过汇编的人都会知道答案。非常感谢您的帮助!提前致谢。

【问题讨论】:

  • 清除寄存器很容易:xor 它本身的编码通常比立即移动到寄存器指令更短,后者将寄存器设置为指令中包含的值。乱序执行 CPU 需要识别依赖链,以便它们可以并行执行所有独立的事情。他们总是将xor eax, eax 识别为独立于先前的值,因此它以与mov eax, 0 相同的方式破坏依赖链。

标签: assembly cpu cpu-registers cpu-architecture


【解决方案1】:

我没有看到你的问题的背景。如果你正在设计一个 4 位 CPU,你可能应该比你看起来做的多读一点。

大多数现实世界的 CPU 使用操作码的一些位来描述操作类型(移动、加法、比较等),并使用更多位来描述寻址模式(常量、寄存器、寄存器间接、内存间接等) .)。并非所有 CPU 都为所有操作码提供所有寻址模式(具有此属性的指令集称为“正交”)。

尝试保存“CPU 实现”(= 减少操作码的数量)可能适用于很少使用的“神秘”指令(或例如浮点运算),但不适用于将常量值移动到一个寄存器。

【讨论】:

  • 感谢您的 asnwer 和新术语(操作码,正交)!抱歉,我知道这个问题可能很愚蠢,但我只是一个自学的,完全没有经验的青少年爱好者,所以关于这个主题的书籍和文章对我来说很难解码(重新阅读直到你理解为止),这就是为什么有时(比如这次)我尝试自己设计东西,结果这些已经在很久以前解决了问题。对不起。
【解决方案2】:

每种处理器架构、x86、arm、mips 等都有自己的方法。如果您不能以某种方式对常量进行操作,那么您肯定无法充分利用处理器。

首先,并非所有处理器都使用寄存器,有些是基于堆栈的,例如,尽管以某种方式在堆栈上放置一个常量,但您也会遇到同样的问题。

有两种基本方法,在大多数处理器上都可以找到。一个是按照您所暗示的,有指令指出这是一个立即移动(立即意味着常数在指令本身中编码)进行注册,术语会有所不同,但操作码,寄存器号和立即值被编码在指令中。取决于 cpu,尽管您可能无法在一条指令中加载整个寄存器,例如固定长度指令集,但您无法将操作码、寄存器编号和 32 位值放入 32 位中,例如 ARM 和 MIPS 可以一次只加载一部分寄存器。加载一个 0x00000078,然后或在 0x00005600 中,然后或在 0x00340000 中,然后或在 0x12000000 或在另一个架构上加载 0x00005678 和或在 0x12340000 中,结果为 0x12345678。

第二种方法是将常量放在程序内存中,通常称为 .text,然后使用一条指令将数据从内存加载或移动到寄存器,使用 pc 相对寻址。 pc 程序计数器,基本上是程序员和汇编程序(读取汇编语言并从中生成机器代码的程序)的组合,已经放置了要加载的指令和要加载的数据,基本上说,取您现在正在执行的指令并添加一些数字 X 并生成我要读取并加载到此寄存器中的常量的地址。第二种方法适用于大多数指令集,您现在可以根据指令集的规则将任何大小的常量加载到您想要的寄存器中,不需要两个或四个或更多指令来拼凑您想要的常量在这种情况下对于固定指令长度的指令集,它确实会花费您一个内存周期,这可能会或可能不会影响性能。如果您考虑可变长度指令集,那么常量本身就是指令流中的单独读取,因此架构之间的权衡确实没有任何不同。

无论指令集有多旧或多新,它们在历史上都是相似的,因为它们是不同的。从旧到新的指令集倾向于使用几个或更多的寄存器,有一个程序计数器,有 alu 操作,加和,或,非,异或等。有一种读写内存的方法(加载和存储),并有使用即时值的能力。较旧的 cisc 处理器和/或可变长度指令集处理器提供了更多这些指令,每个 alu 操作都能够使用全宽立即数,诸如此类,并且当您尝试使用 risc 提高性能时,您牺牲了这些特性用于更快的流水线、更多指令,但它们移动得更快、更顺畅,从而产生整体更快的执行(或其他特性)。

指令集信息在网上供您使用。 pdp-11 或 msp430 是一个很好的第一个指令集,我经常建议在学习汇编时使用模拟器而不是硬件,首先避免使用 x86,直到你有一个或两个其他指令集。 msp430/pdp11、arm、mips、avr 等。在一两次之后,pdp8 确实很有趣且具有教育意义,当然您可能想继续挖掘 4004 或 8008,然后逐步升级到 6502、6800 和 8080诸如此类。

【讨论】:

  • 是的,直接从 ROM 读取值是个好主意!它为其他指令节省了很多插槽!非常感谢!并再次感谢您提供可分析的(如果有这样的词)CPU。我有这个想法,看了维基百科上的 x86 指令集,真的很气馁。这些看起来一点也不可怕!
猜你喜欢
  • 2019-07-03
  • 2013-06-25
  • 2011-03-25
  • 2018-02-24
  • 1970-01-01
  • 1970-01-01
  • 2013-06-16
  • 1970-01-01
  • 2015-06-26
相关资源
最近更新 更多