如何将变量放在 SDCC 中的特定内存位置
How to put a variable at a specific memory location in SDCC
对于低级编程,有时有必要说,在给定的内存位置,这是我的地址。对于这个post,例子就是PIC16F886及相关单片机中的PIR1
寄存器。它总是在地址 0x000C 处找到。
我采用了这种方法:
#define pir1 (*(uint8_t*)0xc)
现在我可以用 pir1 |= 0x40
之类的东西给变量赋值(好吧,我会使用 #defined 常量而不是幻数,但你明白我的意思了)。这在 GCC 上编译得很好,即使我使用 -Wextra -Wall
也没有警告。为了检查我的假设,GCC 吐出以下 x86_64:
movl , %eax
movb , (%rax)
正是我想要的(好吧,我现在确定为什么它是 eax
片刻和 rax
片刻,这可能是另一个愚蠢的 x86 怪癖,但无关紧要,因为我想要 PIC14 代码)
现在,为了以 PIC14 为目标,我实际上正在使用 SDCC 编译器。我是这样调用的
sdcc --std-c99 -mpic14 -p16f886 --use-non-free source.c
上面以#define
开头的代码给出了以下警告:
source.c:412: warning 88: cast of LITERAL value to 'generic' pointer
from type 'const-int literal'
to type 'unsigned-char generic* fixed'
我试过这样做:
__code __at (0xc) uint8_t PIR1;
但这会导致错误消息
error 33: Attempt to assign value to a constant variable (=)
当我尝试做作业时。
所以我的问题是我是否缺少在 C 中执行此操作的惯用方法?为什么 SDCC 警告我?我在这里忽略了一些特定的 SDCC 特定恐惧吗?
“警告 88:将 LITERAL 值转换为 'generic' 指针”似乎是误报。您的宏在语法方面或语言方面都没有错。 C 标准明确允许此类转换,请参阅 C17 6.3.2.3/5:
An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
(在这种情况下对齐和陷阱无关紧要。)
一般的嵌入式系统编译器,尤其是 PIC 编译器,因不符合标准 C 而声名狼藉。因此,您要么必须弄清楚如何禁用损坏的警告,要么考虑使用不同的编译器。
与警告无关,您还有一个严重的错误,即缺少 volatile
。我建议研究这个:How to access a hardware register from firmware?
关于警告,它可能是编译器中的错误。如前所述,您必须使用 (volatile uint8_t*)0xc
代替
进行内存映射访问
SDCC 中绝对寻址的标准方法是通过编译器扩展,但您做错了。 __code __at (0xc) uint8_t PIR1;
将变量放在不可写的代码段中。这就是您看到错误 error 33: Attempt to assign value to a constant variable (=)
的原因。请记住 PIC14 使用哈佛架构。如果地址在 RAM 中,则使用
volatile __data __at (0xc) uint8_t PIR1;
如果它在扩展数据中,则使用
volatile __xdata __at (0xc) uint8_t PIR1;
请参阅文档中的 Absolute Addressing
对于低级编程,有时有必要说,在给定的内存位置,这是我的地址。对于这个post,例子就是PIC16F886及相关单片机中的PIR1
寄存器。它总是在地址 0x000C 处找到。
我采用了这种方法:
#define pir1 (*(uint8_t*)0xc)
现在我可以用 pir1 |= 0x40
之类的东西给变量赋值(好吧,我会使用 #defined 常量而不是幻数,但你明白我的意思了)。这在 GCC 上编译得很好,即使我使用 -Wextra -Wall
也没有警告。为了检查我的假设,GCC 吐出以下 x86_64:
movl , %eax
movb , (%rax)
正是我想要的(好吧,我现在确定为什么它是 eax
片刻和 rax
片刻,这可能是另一个愚蠢的 x86 怪癖,但无关紧要,因为我想要 PIC14 代码)
现在,为了以 PIC14 为目标,我实际上正在使用 SDCC 编译器。我是这样调用的
sdcc --std-c99 -mpic14 -p16f886 --use-non-free source.c
上面以#define
开头的代码给出了以下警告:
source.c:412: warning 88: cast of LITERAL value to 'generic' pointer
from type 'const-int literal'
to type 'unsigned-char generic* fixed'
我试过这样做:
__code __at (0xc) uint8_t PIR1;
但这会导致错误消息
error 33: Attempt to assign value to a constant variable (=)
当我尝试做作业时。
所以我的问题是我是否缺少在 C 中执行此操作的惯用方法?为什么 SDCC 警告我?我在这里忽略了一些特定的 SDCC 特定恐惧吗?
“警告 88:将 LITERAL 值转换为 'generic' 指针”似乎是误报。您的宏在语法方面或语言方面都没有错。 C 标准明确允许此类转换,请参阅 C17 6.3.2.3/5:
An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
(在这种情况下对齐和陷阱无关紧要。)
一般的嵌入式系统编译器,尤其是 PIC 编译器,因不符合标准 C 而声名狼藉。因此,您要么必须弄清楚如何禁用损坏的警告,要么考虑使用不同的编译器。
与警告无关,您还有一个严重的错误,即缺少 volatile
。我建议研究这个:How to access a hardware register from firmware?
关于警告,它可能是编译器中的错误。如前所述,您必须使用 (volatile uint8_t*)0xc
代替
SDCC 中绝对寻址的标准方法是通过编译器扩展,但您做错了。 __code __at (0xc) uint8_t PIR1;
将变量放在不可写的代码段中。这就是您看到错误 error 33: Attempt to assign value to a constant variable (=)
的原因。请记住 PIC14 使用哈佛架构。如果地址在 RAM 中,则使用
volatile __data __at (0xc) uint8_t PIR1;
如果它在扩展数据中,则使用
volatile __xdata __at (0xc) uint8_t PIR1;
请参阅文档中的 Absolute Addressing