0

I'm attempting to use Sourcetrail (https://www.sourcetrail.com/) to quickly get into some old embedded c/c++ source code for the pic18 series of microcontrollers.

I get errors when importing the hardware include files, which uses an exotic method to define the hardware address of the bit addressable hardware registers, such as the below from 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;

As you probably guessed, SourceTrail is confused by the @ 0xF38 part and expect just a semicolon. The method is used by a number of other c/c++ compilers for embedded systems, so I assume a simple fix exists.

Edit:

First, to clarify: The @ is used to place the volatile variable at a specific place in the memory map, either as a bit or a byte address. (Slightly similar to how the 8086 CPU had memory and IO addressing systems). It's used in the global includes (for hundredts of different microcontrollers) that in this case came with the MPLab c/c++ compiler. For analysis purpuse I can make a copy of the global include files, and set up a different path to the global includes in SourceTrail - so they can be modified as much as needed. I would prefer to not touch the project files, as they still need to compile in the original setup.

While attempting @Antti Haapala answer, I found the following types of usage that needs to be taken into account:

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

I can not find __bit defined anywhere, but it's a special construct that holds the bit address (not byte address) of the bit.

fsteff
  • 543
  • 5
  • 19
  • Do you use C or C++? – 12431234123412341234123 Oct 06 '20 at 13:31
  • The current project I have at hand is written in C, but the compiler is a C/C++ compiler and uses the same header files for both. – fsteff Oct 06 '20 at 13:44
  • The part about `__bit` is a different issue, and should be a different question, otherwise it renders the existing answers incomplete through no fault of their own. `__bit` is not defined as a macro or typedef, because there is no standard C equivalent. Rather it is necessarily a built-in data type. Given that a bit may only have a value 0 or 1, you could use `#define __bit _Bool`. Static analysis might complain about implicit conversions, but at least it will be syntactically and largely semantically valid. – Clifford Oct 06 '20 at 16:53
  • Thanks @Clifford I’ll test more and update the question tomorrow. – fsteff Oct 06 '20 at 17:08

3 Answers3

3

@ is not a valid token in C, so you cannot use it as a macro identifier either. The easiest solution would be to handle the @ address with a macro, i.e.

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

extern volatile ANSELAbits_t ANSELAbits AT(0xF38);

The first definition should be guarded by a macro that is used only on the target. It should be quite easy to do the change with a simple Perl script like

perl -pi -e 's/@\s*([0-9a-fA-FxX]+)/AT($1)/g' *.c *.h

If this @ syntax is used in the vendor-provided header files as is, then shame on them.

  • The @ syntax has been used by compiler providers for small PIC, ARM, and other microcontrollers for at least 20 years. – fsteff Oct 06 '20 at 11:06
  • If I were writing a generic C source code transforming program, I would consider the C standard, the common extensions, the many most popular compilers. Some random embedded compiler might be important in the field of embedded software development and in terms of installed device base but when it comes to number of lines of code written then they're hardly a fraction of a percent. – Antti Haapala -- Слава Україні Oct 06 '20 at 11:18
  • I think you would be surprised about how many places embedded systems based on those tiny microcontrollers and compilers are used. But I get your point and I would do the same as you just wrote. Vensors should follow the standards - or extend the standards! – fsteff Oct 06 '20 at 11:23
  • More trivial info. While modifying the files according to the suggested solution, I spotted a file named __at.h, containing `#define __at(x) __attribute__((address(x)))`. – fsteff Oct 06 '20 at 12:13
  • @fsteff :-D so they *did* have a more compliant solution. And `__attribute__` would be something that anyone supporting GCC/Clang would probably know of, or at least it could be `#define`d away more easily if needed. – Antti Haapala -- Слава Україні Oct 06 '20 at 13:45
  • Well. They have it in a separate file, it's just not references anywhere. Still haven't made any of it work yet. – fsteff Oct 06 '20 at 13:48
  • 1
    @fsteff: Nothing an otherwise-conforming implementation might do with a C source file that would contain an unquoted `@` or `$` in the preprocessor output would render it non-conforming. Don't blame vendors for "not following the Standards"--blame the people in charge of standards for refusing to recognize constructs that are often needed when targeting embedded systems, and would have a clear meaning (albeit not always a useful one) on any system that meaningfully processes conversions between integers and pointers. – supercat Oct 07 '20 at 21:13
  • 1
    I ended up using this method but had to make a number of other changes. Will make a summary and reference here when It's all done. – fsteff Oct 08 '20 at 09:34
1

For teh Microchip C18 compuler:

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

Then if rewrite:

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

as

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

then when MCHP_C18 is not defined it will pre-process to:

extern volatile _Bool ABDEN1;

_Bool is not quite the same as __bit of course but has close enough semantic behaviour to be useful for this purpose perhaps.

Clifford
  • 88,407
  • 13
  • 85
  • 165
0

So, the purpose of the @ token is to have the variable at a specific address? So why not have a variable like macro that accesses the memory through a hardcoded pointer?

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

Or if you don't mind having the * operator sprinkled through you source code, you can get rid of the macro:

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

And before somebody complains about UB. Yes, turning integers into pointers is not portable, but should work on most architectures where reading specific memory addresses makes sense.

Personally i prefer the pointer variant. The * and -> operators explicitly shows that you are accessing stuff at a specific memory position:

// 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"?
HAL9000
  • 2,138
  • 1
  • 9
  • 20
  • I'm trying to analyze the existing project, and want to change as little as possible. Preferably by modifying the global includes of the compiler, instead of the project files. I updated the question to clarify. – fsteff Oct 06 '20 at 13:41