【问题标题】:What is a circular shift with extend used for?什么是带扩展的循环移位?
【发布时间】:2018-05-17 05:48:23
【问题描述】:

我记得在汇编课上,我们学习了 m68k 处理器,你可以做 3 种班次。线性移位、循环移位和带扩展的循环移位。

最后一个,带扩展的循环移位,基本上将所有位向左或向右旋转,但它会将最外面的位放入扩展位,然后再将其移动到开头(如果您再次移位 1)。

我画了一张小图:

基本上,第 33 位用于循环移位,但当然不会出现在 32 位字中。第 33 位是处理器的 X 标志,代表扩展。您可以轻松地使用任何状态标志,例如进位标志,但我猜摩托罗拉的人想要保留该标志,这样它就不会被覆盖,以防您在中间需要进位标志来执行其正常职责一些算法也需要用extend来旋转。

无论如何,用 extend 旋转的目的是什么?它是干什么用的?它有什么用?看起来很奇怪。为什么你需要一个 33 位?

我已经阅读了 thisthis 这两个相关的问题,但他们没有谈到循环移位with extend

我知道正常轮班的一些用途。基本上是除以二,或测试可除性,并对位进行随机排列。像那样的东西。但我想不出为什么您需要在旋转中插入一些扩展位,但结果中没有出现。

编辑:我对它的任何用途感兴趣,无论是现代的还是旧的,不管它是否在 m68k 上。 m68k 只是我遇到的第一个位置(我什至从未在那里使用过)。

【问题讨论】:

    标签: assembly bit-shift cpu-architecture instruction-set 68000


    【解决方案1】:

    ROXL 对于非破坏性测试位非常有用,与 BTST.x 指令(仅适用于 8 位和 32 位大小)相比,可以节省相当多的指令。一旦你这样做了,旋转不止一个位置也可以让诸如跳过位之类的事情成为可能。

      ROXL.W #4,D0      ; shift bit 12 into carry and X
      BCC.S isNotSet    ; branch if bit is not set
      BSR isSet         ; do whatever you want
    isNotSet:
      ROXL.W #11,D0     ; rotate around to reset to previous value
    

    【讨论】:

      【解决方案2】:

      在 x86(以及大多数具有此指令的体系结构)上,额外的位是进位标志,很多东西都可以设置该标志。向左或向右循环进位可让您将进位位移回其他寄存器。有趣的是,m68k 使用不同的标志进行扩展旋转。

      我对 m68k 已经不是很熟悉了,所以我主要谈谈其他拱门。 (但是apparently that's what you want :)

      此类指令通常在功能远不如 x86 或 m68k 的微控制器上可用。或者由于操作码空间有限(和解码复杂性),某些 CPU 具有循环进位 1 而不是常规移位指令。如果要移入零,请确保先清除标志。

      8051 是这样的:只左/右旋转 1,并且带进位左/右旋转 1,不移位。请参阅 ISA 参考手册中的 rlc。如果可能,当您想通过将rlc 放在其他可以清除进位的内容之后,避免使用clr 指令。

      我认为扩展循环移位通常使用进位标志,而不是像 m68k 那样使用它自己的 X 位。

      无论如何,扩展精度旋转对于 CPU 来说是一种传统/预期,但在更有限的 CPU 上有更多用途。


      对于一个寄存器,rcl reg, 1adc reg,reg的操作相同:将旧内容左移1,并将低位设置为CF。旋转或 adc 移出的位成为 CF 的新值。因此,如果 RCL 可与内存操作数一起使用,或者(对于奇怪的情况)计数大于 1,则 RCL 只是指令集的非冗余部分。(不过,向右旋转的版本不是冗余的。)

      IDK 为什么你曾经使用过 count > 1。在现代 x86 上,如果 count=1,rotate-through-carry 相当快,但对于可变 count 或固定 count>1 肯定很慢。 IDK 鸡/蛋问题的走向:CPU 设计人员没有让它快,因为没有人使用它,或者人们停止使用它,因为它很慢。但可能是前者,因为我不记得曾经见过提到的用于循环进位超过 1 位的用途。

      对于扩展精度移位,x86 有一个双移位指令 (shld / shrd dst, src, count) 移位 dst,从 src 移入位,而不是零或符号位的副本。它不适用于 2 个内存操作数,因此扩展精度移位循环必须使用单独的指令加载和存储寄存器。这比使用 rcr dword [edi], 1 / sub edi, 4 的循环要大得多,但在现代 x86 上,代码大小很少成为问题,并且使用单独的指令进行加载/存储并不慢。)更重要的是,shrd 移动多个位一次,因此您可以循环一次数组以实现多精度移位 2 位或更多位。

      扩展循环一次只能在寄存器之间移动一位,因为它使用 1 位存储空间(在标志中)。我认为在 m68k 上,如果您确实想在寄存器之间移动多个位,您可能会复制一个寄存器并使用常规移位 + OR 进行组合。 (或旋转和/或来拆分位。)

      在 AMD CPU 上,shld/shrdrcl/rcr-by-1 慢,但在 Intel CPU 上则相反。 (http://agner.org/optimize/)。


      除了在寄存器之间移动位之外,我真的想不出任何用例。也许如果你移出一点,然后在可能设置或清除 X 位的东西上进行分支,然后将位移回,你可以使用扩展旋转对低位或高位做一些事情?但是,您通常可以更轻松地使用 AND、OR 或 XOR 与常量进行相同操作。

      【讨论】:

      • 另一个用例是填充位缓冲区。您使用1 初始化缓冲区并使用rclcf 中的值移动到缓冲区中来填充它。当cf 设置在rcl 之后时,您就知道缓冲区已满并且可以将其清空,而无需跟踪计数器或类似内容。
      • (I only noticed you were specifically asking about m68k after writing most of this answer). 实际上,我对旋转和扩展的任何使用都很感兴趣。 m68k 正是我第一次遇到它的地方。我对 OP 进行了编辑。
      • IDK why you'd ever use a count > 1我也没有。我当然可以想到线性移位和循环移位(没有扩展)的用途,但是您知道我什至不记得 m68k 指令集是否允许将立即值传递给移位操作,或者您是否必须循环通过指令n 次。
      • @DrZ214:好的,很高兴我仍然发布了这个答案。在使用 CF 的 x86 上,您可以通过将位从 CF(以其他方式设置)转移到寄存器中来执行更多奇怪的技巧。正如 Fuz 指出的那样,您可以通过这种方式设置位图。
      • @DrZ214:增加了一个关于8051的部分,它只有轮换,没有定期轮换。
      【解决方案3】:

      想象一下,您想在一个单词的位上重复分支。只要设置标志可用于分支或其他条件指令(它在 x86 上),rcl reg, 1rcr reg, 1 的简单循环就可以让您做到这一点。基于移出位设置标志的移位提供相同的功能(尽管最终会破坏正在移位的字)。

      在相反的情况下,假设您想要基于一系列真/假测试构建位图。在测试中设置的标志中移动的旋转可以让您有效地执行此操作(不清楚是否可以通过这种方式设置 68k X 标志,但 x86 上的进位标志肯定可以)。

      【讨论】:

        【解决方案4】:

        假设您想将一个 32 位字向右移动,但您只有 16 位寄存器。为此,您必须将 32 位字的两个 16 位部分向右移动,并将从高位字移出的位转移到低位字中。

        如果您只有逻辑移位,这很麻烦,因为您必须手动修复该位。循环进位指令允许您将需要传输的位保留在进位标志中,并一次性将其移入。循环进位指令将移出的位放在进位标志中,因此您可以轻松地将其链接在一起以右移任意大小的数据。

        【讨论】:

        • fuz 所说的,实际上您还可以通过这些旋转将位图图像(B&W 1b 位图类型)向左/向右移动单个像素。在 ZX Spectrum 上将整个屏幕向右移动 1 个像素,您可以使用 rr (hl) inc hl 指令的展开循环(或者更确切地说是 inc l,您知道地址 l < 255 的低 8 位)......仍然没有足够快(甚至展开并部分inc)以在单帧中移动整个屏幕,最多只有大约55%的屏幕可以通过这种方式移动(更智能的游戏确实在内存中使用预先旋转的精灵以避免较慢的旋转说明)。
        • 这是一个正确的答案,尽管不关注只有 32 位寄存器的 m68k。如果你把所有地方的位数加倍,它就会适合。
        • @tofro 显然,在尝试仅使用 32 位寄存器移动 64 位数字时,您会遇到同样的问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多