【问题标题】:GCC extended asm differentiating literal vs registerGCC 扩展 asm 区分文字与寄存器
【发布时间】:2017-07-25 04:39:28
【问题描述】:

我发现自己广泛使用内联 asm,并且经常希望能够在给定的 asm 中使用寄存器文字,但是我看不出如何使用Microchip XC16 套件。

据我所知,您需要手动编码文字符号#,这与前缀不兼容。这意味着以下代码无法编译:

asm("MOV %1, %0" : "=r" (res) : "i" (1));
Invalid operands specified ('mov 1,w0').

但以下是:

asm("MOV #%1, %0" : "=r" (res) : "i" (1));

这当然与寄存器不兼容:

asm("MOV #%1, %0" : "=r" (res) : "ri" (x));
Invalid operands specified ('mov #w0,w0').

所以在我看来,Microchip 没有遵循 GCC 约定,我认为文字符号应该嵌入到操作数中,这使得它特别难以使用。

我想知道是否有机会.. 有人对如何解决这个问题有任何好的想法吗?

现在我将 __builtin_constant_p 作为附加参数传递,然后我在 asm 中按如下方式打开 .if,但要说它变得笨拙快速将是轻描淡写。

asm(".if %[isk]  \n"
    "MOV #%1, %0 \n"
    ".elseif     \n"
    "MOV %1, %0  \n"
    ".endif      \n"
    : "=r" (res)
    : "ri" (x), [isk] "i" (__builtin_constant_p(x));

如果isk 为真,我什至不相信 GCC 保证 %1 将是一个文字,这意味着必须 if-then-else 将其全部阻止在 C 端......叹息。


澄清MOV 只是一个示例指令。这些处理器 (dsPIC33E) 具有零开销的单指令和多指令循环,需要 asm 才能利用,其语法如下所示:

/* this code demonstrates compilation failure if cnt is a constant
 * as there is no # prefix before the %[cnt] */
asm("REPEAT %[cnt]        \n"
    "  MOV [%0++], [%1++] \n"
    : "+r" (src), "+r" (dst), "=m" (*dst)
    : "m" (*src), [cnt] "ri" (cnt));

这个 memcpy 循环需要 cnt+1 个周期来执行,由于流水线,它实际上比完全展开循环快两倍,比每次迭代分支快 6 倍。除了它们的多指令 DO 循环变体外,它们对于充分利用这些处理器非常重要。

【问题讨论】:

  • 您真正想要解决的问题是什么?我确定您不会尝试编写单个 MOV 语句。也许有一种方法可以完全避免MOV
  • asm("MOV %1, %0" : "=r" (res) : "i" (1)); 应该编译,并且在针对 x86 的 GCC 中编译。 i is a valid constraint, meaning an immediate integer operand。所以这显然是你的编译器中的一个错误。不过,就像弗洛里安所说的那样,您需要在内联汇编中编写MOV 指令,或者在内联汇编中编写非常多的代码根本,这很奇怪。为什么你会发现自己“大量使用内联 asm”?
  • @CodyGray,x86 不同,因为直接操作数不需要前缀。
  • 啊,我明白你的意思了。它看起来确实像一个编译器错误/缺失的功能。
  • @CodyGray,我最初考虑的是intel 语法。但你是对的,GCC 根据需要为att 合成$。如果这个目标不这样做,肯定看起来像一个编译器错误。看起来 Microchip 没有向公众提供其编译器的源代码,所以我无法快速查看它们以确认。

标签: gcc embedded inline-assembly microchip xc16


【解决方案1】:

我找到了一种在 asm 中检测给定参数是否为文字的方法,它远非理想,但它似乎有效。

首先,在一个asm头文件中,为每个寄存器标记一个符号:

.irp r,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
  .set _IS_REG_w&r&, 1 ; mark all registers as "REGs"
  .set _IS_REG_W&r&, 1
.endr

然后使用:

.ifdecl _IS_REG_%0
  REPEAT %0
.else
  REPEAT #%0
.endif

可以封装在 asm 宏中:

.macro REPEATN cnt
    .ifdecl _IS_REG_&cnt&
        REPEAT \cnt
    .else
        REPEAT #\cnt
    .endif
.endm

为了方便嵌入到内联汇编中:

void DelayCycles(int count)
{
    asm("REPEATN %[cnt]    \n"
        "    NOP           \n"
        :
        : [cnt] "ri" (count));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-05
    相关资源
    最近更新 更多