用于AVR RTOS的内联C汇编程序宏

时间:2017-08-19 07:49:08

标签: c assembly embedded

我正在尝试为AVR编写抢占式调度程序,因此我需要一些汇编程序代码......但我没有使用汇编程序的经验。但是,我在一些C宏中编写了我认为需要的所有汇编代码。在编译时,我得到一些与汇编程序有关的错误(需要常量值和乱码和乱码),这让我觉得我的宏中的某些东西是不正确的......

以下宏load_SP(some_unsigned_char,some_unsigned_char)将堆栈指针设置为已知的内存位置......我将该位置保存在全局struct aux_SP中;

与load_PC(...)类似的东西是在堆栈上加载的,一个程序计数器:“func_pointer”,顾名思义,它实际上是指向函数的指针。我假设程序计数器和函数指针都表示在2个字节上(因为闪存足够小)

为此我使用处理器寄存器R16。为了保持该寄存器不变,我首先使用宏“save_R16(tempR)”保存其值,并使用宏“load_R16(tempR)”恢复其值,其中“tempR”可以看作是全局C变量。

这只是写在头文件中。这与另外两个宏(由于它们的大小不在这里写)“pushRegs()”和“popRegs()”基本上推送然后弹出所有处理器寄存器是我的汇编程序代码......

我该怎么做才能纠正我的宏?

// used to store the current StackPointer when creating a new task until it is restored at the
// end of createNewTask function.
struct auxSP
{
    unsigned char auxSPH;
    unsigned char auxSPL;
};

struct auxSP cSP = {0,0};

// used to restore processor register when using load_SP or load_PC macros to perform
// a Stack Pointer or Program Counter load.
unsigned char tempReg = 0;

////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// assembler macros begin ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

// save processor register R16
#define save_R16(tempR)                                 \
    asm volatile(                                       \
            "STS tempR, R16                     \n\t"   \
                );

// load processor register R16
#define load_R16(tempR)                                 \
        asm volatile(                                   \
                    "LDS R16, tempR             \n\t"   \
                    );

// load the Stack Pointer.              Warning: Alters the processor registers
#define load_SP(new_SP_H, new_SP_L)                     \
    asm volatile(                                       \
                "LDI R16, new_SP_H              \n\t"   \
                "OUT SPH, R16                   \n\t"   \
                "LDI R16, new_SP_L              \n\t"   \
                "OUT SPL, R16                   \n\t"   \
                );

// load the Program Counter on stack.   Warning: Alters the processor registers
#define load_PC(func_pointer)                           \
    asm volatile(                                       \
                "LDS r16, LOW(func_pointer)     \n\t"   \
                "PUSH r16                       \n\t"   \
                "LDS r16, HIGH(func_pointer)    \n\t"   \
                "PUSH r16                       \n\t"   \
                );

2 个答案:

答案 0 :(得分:1)

您的主要参考资料应为http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

避免使用“unsigned char” - 使用“uint8_t”,因为它更短更明确。避免使用宏 - 尽可能使用静态内联函数。不要为auxSP创建自己的结构,特别是不使用与目标通常使用的不同的字节序排序 - 只需使用uint16_t。当你可以用C语言编写它们时,不要在汇编中写东西。并且不要拆分需要组合在一起的asm语句(例如在一个语句中保留R16,然后在第二个语句中使用它)。

这会让我们离开?

自从我做了很多AVR编程以来已经很长时间了,但这可能会让你开始:

static inline uint16_t read_SP(void) {
  uint16_t sp;
  asm volatile(
    "in  %A[sp], __SP_L__ \n\t"
    "in  %B[sp], __SP_H__ \n\t"
  : [sp] "=r" (sp) :: );
  return sp;
}

static inline void write_SP(uint16_t sp) {
  asm volatile(
    "out  __SP_L__, %A[sp] \n\t"
    "out  __SP_H__, %B[sp] \n\t"
  :: [sp] "r" (sp) : );
}

typedef void (*FVoid)(void);
static inline void load_PC(FVoid f) __attribute__((noreturn));
static inline void load_PC(FVoid f) {
  asm volatile(
    "ijmp"
  :: "z" (f) );
  __builtin_unreachable();
}

您可能还需要确保在使用任何这些之前禁用中断。

答案 1 :(得分:-1)

以下是我在AVR平台上执行的C代码示例。它不是宏,而是功能,因为它更适合我。

void call_xxx(uint32_t address, uint16_t data)
{
    asm volatile("push r15"); //has to be saved
    asm volatile("ldi r18, 0x01");  //r15 will be copied to SPMCSR
    asm volatile("mov r15, r18"); //copy r18 to r15 (cannot be done directly)
    asm volatile("movw r0, r20"); //r1:r0 <= r21:r20 //should conatain "data" parameter
    asm volatile("movw r30, r22"); //31:r30<=r23:r22 // should contain "address" parameter ...
    asm volatile("sts 0x5b, r24"); //RAMPZ
    asm volatile("rcall .+0"); //push PC on top of stack and never pop it
    asm volatile("jmp 0x3ecb7");  //secret function
    asm volatile("eor r1, r1"); //null r1
    asm volatile("pop r15");  //restore value

    return;
}

也可以在没有\n\t的情况下尝试这可能是&#34;&#34;&#34;

所需的恒定值问题可能来自:

#define save_R16(tempR)                                 \
    asm volatile(                                       \
            "STS tempR, R16                     \n\t"   \
                );

为此,我不太确定,但STS(和其他)需要一个可能需要在编译时修复的地址。因此,根据您使用宏的方式,它可能无法编译。如果未修复tempR,则可以使用函数而不是宏。