配置 SourceTrail 以接受带有 @ 语法的嵌入式 c/c++ 头文件

Configure SourceTrail to accept embedded c/c++ header files with @ syntax

我正在尝试使用 Sourcetrail (https://www.sourcetrail.com/) 快速进入一些旧的嵌入式 c/c++ pic18 系列微控制器的源代码。

我在导入硬件包含文件时遇到错误,它使用一种奇特的方法来定义位可寻址硬件寄存器的硬件地址,例如下面来自 pic18f26k22.h.

typedef union {
    struct {
        unsigned ANSA0                  :1;
        unsigned ANSA1                  :1;
        unsigned ANSA2                  :1;
        unsigned ANSA3                  :1;
        unsigned                        :1;
        unsigned ANSA5                  :1;
    };
} ANSELAbits_t;

extern volatile ANSELAbits_t ANSELAbits @ 0xF38;

正如您可能猜到的那样,SourceTrail 被 @ 0xF38 部分弄糊涂了,只需要一个分号。许多其他 c/c++ 嵌入式系统编译器都使用该方法,因此我假设存在一个简单的修复方法。

编辑:

首先,澄清一下:@用于将易失性变量放置在内存映射中的特定位置,可以是位地址也可以是字节地址。 (与 8086 CPU 具有内存和 IO 寻址系统的方式略有相似)。它用于全局包含(用于数百种不同的微控制器),在这种情况下,MPLab c/c++ 编译器附带了它。出于分析目的,我可以制作全局包含文件的副本,并在 SourceTrail 中设置全局包含文件的不同路径 - 因此可以根据需要对其进行修改。我宁愿不碰项目文件,因为它们仍然需要在原始设置中编译。

在尝试@Antti Haapala 回答时,我发现需要考虑以下类型的用法:

extern volatile unsigned char           BAUDCON1            @ 0xFB8;

#ifndef BANKMASK
#define BANKMASK(addr) ((addr)&0FFh)
#endif
extern volatile __bit                   ABDEN1              @ (((unsigned) &BAUDCON1)*8) + 0;
#define                                 ABDEN1_bit          BANKMASK(BAUDCON1), 0

我找不到在任何地方定义的 __bit,但它是一个特殊的结构,用于保存位的位地址(不是字节地址)。

@ 在 C 中不是有效的标记,因此您也不能将其用作宏标识符。最简单的解决方案是使用宏处理@地址,即

#ifdef somethingsomething
#define AT(address) @ address
#else
#define AT(address)
#endif

extern volatile ANSELAbits_t ANSELAbits AT(0xF38);

第一个定义应由仅在目标上使用的宏保护。使用像

这样的简单 Perl 脚本进行更改应该很容易
perl -pi -e 's/@\s*([0-9a-fA-FxX]+)/AT()/g' *.c *.h

如果这个 @ 语法在 vendor-provided 头文件中按原样使用,那就丢脸了。

所以,@ 令牌的目的是让变量位于特定地址?那么为什么不使用像宏这样的变量来通过硬编码指针访问内存呢?

#define ANSELAbits (* (ANSELAbits_t *) 0xF38) 

或者,如果您不介意让 * 运算符散布在您的源代码中,您可以删除宏:

static ANSELAbits_t * const ANSELAbits_ptr = (ANSELAbits_t *) 0xF38;

在有人抱怨 UB 之前。是的,将整数转换为指针不可移植,但应该适用于读取特定内存地址有意义的大多数体系结构。

我个人更喜欢指针变体。 *-> 运算符明确表明您正在访问特定内存位置的内容:

// This is in my humble opinion clearer code:
ANSELAbits_ptr->ANSA0 = 1;
// or
(* ANSELAbits_ptr).ANSA0 = 1; 

// ...rather than this: 
ANSELAbits.ANSA0 = 1;   // How do we know that ANSELAbits is "Magic"?

对于 Microchip C18 编译器:

#if defined MCHP_C18
  #define AT(address) @ address
#else
  #define AT(address)
  #define __bit _Bool
#endif

那么如果重写:

extern volatile __bit ABDEN1 @ (((unsigned) &BAUDCON1)*8) + 0;

作为

extern volatile __bit ABDEN1 AT((((unsigned) &BAUDCON1)*8) + 0);

然后当 MCHP_C18 未定义时它将 pre-process 到:

extern volatile _Bool ABDEN1;

_Bool 当然与 __bit 不完全相同,但具有足够接近的语义行为,也许可用于此目的。