我正在开发一个小程序,以学习如何在Atmel Studio GCC中混合使用C和Assembly。基本上我正在编写一个C程序来启动程序集中的堆栈指针。当我构建它时,我不断收到错误“操作数超出范围”。我已在程序中多次启动堆栈指针,但无法在该程序的“.s”文件中使用它。我已经让程序在“.s”文件中使用不同的寄存器,所以我不认为这是两个文件之间的连接。任何帮助将不胜感激。
MAIN.C:
#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
extern void setStackPointer(void);
int main(void)
{
DDRB |= 0x20;
setStackPointer();
while (1)
{
PORTB = 0x20;
_delay_ms(500);
PORTB = 0x00;
_delay_ms(500);
}
}
Assembler1.s:
#define _SFR_ASM_COMPAT 1
#define _SFR_OFFSET 0
#include <avr/io.h>
.global setStackPointer
setStackPointer:
ldi r18, lo8(RAMEND-0x20)
out SPL, R18
ldi R18, hi8(RAMEND-0x20)
out SPH, R18
ret
答案 0 :(得分:1)
这里有几个问题。
首先,乔布莱克爵士的评论是对的:没有理由
从0x20
中减去RAMEND
。我的意思是,除非你想分开32
RAM末尾的字节......
其次,自己设置堆栈指针没有意义。最多的
最近的AVR,包括ATmega328P,SP
会自动初始化
由RAMEND
的硬件。 C.F.数据表。如果不是这样的话
足够的,它由C运行时再次初始化,正常运行
如果编译,链接到您的程序(甚至是100%汇编程序)
它与gcc。
第三,来自avr-libc documentation:
要获得更多向后兼容性,请在开头插入以下内容 旧的汇编源文件:
#define __SFR_OFFSET 0
这会自动从I / O空间地址中减去0x20,但它是a hack,所以建议更改你的源:包装这样的地址 在此处定义的宏中,如下所示。完成后, <{1}}定义不再是必需的,可以删除。
编写该代码的推荐方法是:
__SFR_OFFSET
如果你真的想使用旧的黑客,请写
setStackPointer:
ldi r18, lo8(RAMEND)
out _SFR_IO_ADDR(SPL), r18
ldi r18, hi8(RAMEND)
out _SFR_IO_ADDR(SPH), r18
ret
在您的计划开始时。并注意双重 在宏名称的开头加下划线。