我正在尝试为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" \
);
答案 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,则可以使用函数而不是宏。