C ++模板参数作为asm块中汇编程序宏的参数(gcc / gas)

时间:2015-08-08 19:37:23

标签: c++ assembly macros arm

我试图在某些asm宏中使用整数模板参数,但我遇到了替换问题。下面是我正在做的(非常)简化版本:

template<int X> void delay() {
    asm __volatile__(
        "  .macro fl_delay dtime, reg=r0    \n\t"
        "    .if (\\dtime > 0)              \n\t"
        "      .set dcycle, (\\dtime / 3)   \n\t"
        "      .set dwork, (dcycle * 3)     \n\t"
        "      .set drem, (\\dtime - dwork) \n\t"
        "      .rept (drem)                 \n\t"
        "        nop                        \n\t"
        "      .endr                        \n\t"
        "      .if dcycle >= 0              \n\t"
        "        mov \\reg, #dcycle         \n\t"
        "        loop_\\@:                  \n\t"
        "        sub \\reg, #1              \n\t"
        "        bne loop_\\@               \n\t"
        "      .endif                       \n\t"
        "    .endif                         \n\t"
        "  .endm                            \n\t"
        "  fl_delay %[X], r0                \n\t"
        : [X] "I" (X)
        :
        : "r0");
} 

宏基本上允许我做循环计数准确的延迟。所以,例如,如果在我的asm代码中我写道:

"  fl_delay 13, r0"

它将延迟完全 13个周期(使用寄存器r0作为循环计数器)。这部分在一堆测试中非常有效。当我想让我的宏的参数取决于模板参数(上面的X)时,问题出现了。如果我(其他地方)写delay<13>();,生成的函数的asm看起来像:

; fl_delay macro definition here 
fl_delay #13, r0

问题是,gnu as的表达式解析器不喜欢#。我怀疑问题是宏中的位,比方说,我做.set dcycle, (\\dtime / 3)\\dtime将替换为#13,使该行.set dcycle, (#13 / 3)(我已经能够通过在某些测试代码中放置该确切的行来验证,因为错误消息是相同的)。

所以,我有两个问题需要找到答案:

  • 有没有办法让我从模板参数中获取int值到asm块而不用前导#? (我已经尝试了一堆asm约束,但它们都把#领先于那里)
  • 如果我不能做到,请问剥离 as .macro参数值的前导字符?我已经做了很多挖掘工作,但是却找不到任何东西。

我不相信我有办法滥用C预处理器来执行此操作,因为它会在任何模板/ C ++解析完成之前运行并进行替换。

(我正在编写的是一些具有非常严格的时序要求的代码,具体取决于所讨论的硬件 - 对于不同类型的硬件,协议几乎相同,时间也不同。我在时钟速度很低(16-48Mhz)的硬件上运行,有时延迟将是0-3个时钟,这足够短,意味着我无法在asm中执行此操作,这就是我使用的原因.macros - 因为那时需要延迟0(因为时钟速度和硬件时序的组合)没有任何东西被发射,如果我需要延迟1,那么单个nop会被发射,等等......)

编辑:我有一个潜在的解决方案,它很难看,所以我将把这个问题留在这里以防人们有另一种选择。我的延迟有多大是有限的,所以我基本上可以做以下事情:

template<int X> void delay() {
    switch(X) {
      case 0: asm __volatile__ (".set X, 0\n\t"); break;
      case 1: asm __volatile__ (".set X, 1\n\t"); break;
      case 2: asm __volatile__ (".set X, 2\n\t"); break;
      case 3: asm __volatile__ (".set X, 3\n\t"); break;
      case 4: asm __volatile__ (".set X, 4\n\t"); break;
      case 5: asm __volatile__ (".set X, 5\n\t"); break;
      case 6: asm __volatile__ (".set X, 6\n\t"); break;
    }
    asm __volatile__(
        "  .macro fl_delay dtime, reg=r0    \n\t"
        "    .if (\\dtime > 0)              \n\t"
        "      .set dcycle, (\\dtime / 3)   \n\t"
        "      .set dwork, (dcycle * 3)     \n\t"
        "      .set drem, (\\dtime - dwork) \n\t"
        "      .rept (drem)                 \n\t"
        "        nop                        \n\t"
        "      .endr                        \n\t"
        "      .if dcycle >= 0              \n\t"
        "        mov \\reg, #dcycle         \n\t"
        "        loop_\\@:                  \n\t"
        "        sub \\reg, #1              \n\t"
        "        bne loop_\\@               \n\t"
        "      .endif                       \n\t"
        "    .endif                         \n\t"
        "  .endm                            \n\t"
        "  fl_delay X, r0                \n\t"
        :
        :
        : "r0");
}

void loop() { delay<5>(); }

这意味着对于delay<5>();实例化,有一个.set X, 5在我的asm块的其余部分之前发出。它会很难看(我的延迟可能会达到120个周期),但它会起作用。

0 个答案:

没有答案