Search code examples
cmacrosc-preprocessorarmcc

Continually increment a macro's value after calling another macro


I am writing a header file with a structured schema in mind. My goal is to define a base address that will increment after calling another macro. The purpose of this is to keep a running count of the new base address and to check at compile time whether or not it exceeds the maximum physical address.

I previously thought of using a global variable to count the address, but this would be resolved at run time and I require this during compile-time, before any binary is outputted so as to prevent possible memory corruption.

Here's what I mean by example:

The following is what I want the header file too look like upon inspection (or something equivalent):

#define DRAM_DEFINE_PTR              0x30000000
#define DRAM_DATA1_BASE              0x30000100
#define DRAM_DATA1_SIZE              0x050
#define DRAM_DATA2_SIZE              0x400
#define DRAM_DATA3_BASE              0x30000600
#define DRAM_DATA3_SIZE              0x300

#define DRAM_DEFINES(x,y)            (...) 
// store base 'x' and size 'y' in a structure and increment DRAM_DEFINE_PTR accordingly

1.     DRAM_DEFINES (DRAM_DATA1_BASE,        DRAM_DATA1_SIZE)
2.     DRAM_DEFINES (0x0,                    DRAM_DATA2_SIZE)   //base is previous base + size
3.     DRAM_DEFINES (DRAM_DATA3_BASE,        DRAM_DATA3_SIZE)
// more DRAM_DEFINES

In reality, the code block below will expand lines 1 and 2 to be:

1.     DRAM_DEFINES (0x30000100,        0x50)
       // DRAM_DEFINE_PTR now equals 0x30000150

2.     DRAM_DEFINES (0x30000150, 0x400)
       // DRAM_DEFINE_PTR now equals 0x30000550

3.     DRAM_DEFINES (0x30000600 , 0x300)
       // DRAM_DEFINE_PTR now equals 0x30000900
and so on

and then at the end of the file have an #error check to ensure we didn't go over the boundary

#if (DRAM_DEFINE_PTR > 0x40000000)
   #error "\nCAPACITY EXCEEDED by ", DRAM_DEFINE_PTR - 0x40000000, " bytes"
#endif

As we can see from above, not every region of memory is to be used completely. Like between 2 and 3 there is 50 bytes of buffer. So this means that base addresses can either be

  • hard coded values using a #define OR
  • offset from previous region's base + the previous region's size

Is this possible within the compiler I'm using (ARMCC RVCT 5.03)?

Thanks in advance


Solution

  • You can update the value of a macro in the course of translating one unit using the Boost Preprocessor library's evaluated slots functionality. It defines several "slots" that can be treated as mutable global variables by preprocessor code, which will let you add to a value as you go along, rather than permanently defining it with a single fixed expression. It's pure standard-compatible C (or C++).

    The main syntactic nuisance is that you have to give the update operation two lines to itself, because it's powered by a #define/#include pair.

    #define DRAM_PTR_SLOT 2    // any slot
    #define DRAM_DEFINE_PTR BOOST_PP_SLOT(DRAM_PTR_SLOT)
    #define SET_DRAM_DEFINE_PTR BOOST_PP_ASSIGN_SLOT(DRAM_PTR_SLOT)
    
    #define BOOST_PP_VALUE 0x30000100 + 0x50
    #include SET_DRAM_DEFINE_PTR    // DRAM_DEFINE_PTR now evals to 0x30000150
    
    #define BOOST_PP_VALUE DRAM_DEFINE_PTR + 0x50
    #include SET_DRAM_DEFINE_PTR    // DRAM_DEFINE_PTR now evals to 0x300001A0
    

    It's not tremendously elegant - there's no way to pack a directive inside another macro, so you can't hide this inside a syntax like the one in the question - but you might be able to at least hide the Boost names under some domain-specific wrapper macros of your own.