【发布时间】:2017-08-19 07:49:07
【问题描述】:
我正在尝试为 AVR 编写一个抢占式调度程序,因此我需要一些汇编代码……但我没有汇编程序的经验。但是,我在一些 C 宏中编写了我认为需要的所有汇编代码。在编译时,我得到了一些与汇编器相关的错误(需要常量值和行和行的垃圾),这让我认为我的宏中有些地方不正确......
下面的宏 load_SP(some_unsigned_char, some_unsigned_char) 将堆栈指针设置为一个已知的内存位置...我将该位置保存在全局结构 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" \
);
【问题讨论】:
-
阅读 gcc 文档如何在内联汇编中使用 C 参数和变量。
-
要成功进行线程切换,您必须将所有寄存器恢复到中断线程时它们所处的状态。这意味着您的定时器中断例程不仅要保存它看到的所有寄存器,还要检查堆栈以恢复由中断硬件逻辑推送到那里的值(PC 的正确值在那里)。编译器生成的 ISR 序言还将一些值压入堆栈。恢复寄存器的顺序也很重要。
-
@MichaelRoy 如前所述,有宏 pushRegs() 将所有寄存器压入堆栈,popRegs() 从堆栈中弹出所有寄存器。这些宏用于其他功能...
-
顺便说一句,AVR 的 RAM 非常少。为多个堆栈保留空间会浪费相当多的 RAM。
-
@MichaelRoy 我为每个堆栈保留 64 个字节......这更多是为了学术用途......我对一些概念感兴趣