Preprocessor not resolving parameter at usage of a port macro Topic is solved

Technical questions regarding the xTIMEcomposer, xSOFTip Explorer and Programming with XMOS.
User avatar
aclassifier
Respected Member
Posts: 319
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Preprocessor not resolving parameter at usage of a port macro

Postby aclassifier » Wed Jan 17, 2018 4:56 pm

The code below, with COMPILES_FINE commented away will not compile. I would have expected PIN_13_LED to be expanded to 1A, but it doesn't seem to be.

Also, when it compiles OK, there is an error message in the .o file about aliasing, see inside main()

I have added the project as compiled OK and with error, in case there is any compiler person wanting to look at this.

Some may see that I am trying to make it easy to port from Arduino. The source file in the attached zip is loaded with comments in that regard. Also, I will blog about this, starting at [1]

[1] http://www.teigfam.net/oyvind/home/technology/164-my-aquariums-data-radioed-through-the-shelf/#porting_to_xmos_xc Disclaimer: no money, no ads, no gifts - Just fun and expenses

Code: Select all

#include <xs1.h>
#include <stdint.h> // uint8_t

typedef enum {LOW,HIGH}   pinval_t; // 0,1

#define PINMODE_OUTPUT_pin_out_1X(num) out port pin_out_##num = XS1_PORT_##num // Usage global only
#define PINMODE_INPUT_pin_in_1X(num)  in  port pin_in_##num  = XS1_PORT_##num // Usage global only

void digitalWrite (out port pin, const pinval_t pinval) {
    pin <: pinval;
}

pinval_t digitalRead (in port pin) {
    pinval_t pinval;
    pin :> pinval;
    return pinval;
}

#define PIN_13_LED    1A
#define PIN_07_BUTTON 1B

#define COMPILES_FINE

#ifdef COMPILES_FINE
    PINMODE_OUTPUT_pin_out_1X(1A); // "pin_out_1A" created
    PINMODE_INPUT_pin_in_1X (1B); // "pin_in_1B"  created
#else
    PINMODE_OUTPUT_pin_out_1X (PIN_13_LED);    // error: use of undeclared identifer `XS1_PORT_PIN_13_LED'
    PINMODE_INPUT_pin_in_1X   (PIN_07_BUTTON); // error: use of undeclared identifer `XS1_PORT_PIN_07_BUTTON'
#endif

int main() {
    pinval_t pinval;
                                       // In __arduino_on_xmos_test.xc.o:
    pinval = digitalRead (pin_in_1B);  // note: object used here
                                       // error: call to `digitalWrite' in `main' makes alias of global 'pin_out_1A'
    digitalWrite (pin_out_1A, pinval); // error: call to `digitalRead' in `main' makes alias of global 'pin_in_1B'

    // digitalWrite (pin_out_1A, digitalRead (pin_in_1B)); // One-liner2
    return 0;
}
Attachments
2018 01 17 __arduino_on_xmos_test with error.zip
The prject as buil t with error
(12.26 KiB) Downloaded 84 times
2018 01 17 __arduino_on_xmos_test with error.zip
The prject as buil t with error
(12.26 KiB) Downloaded 84 times
2018 01 17 __arduino_on_xmos_test.zip
The project as built OK
(32.93 KiB) Downloaded 93 times
2018 01 17 __arduino_on_xmos_test.zip
The project as built OK
(32.93 KiB) Downloaded 93 times
View Solution
CousinItt
Experienced Member
Posts: 88
Joined: Wed May 31, 2017 6:55 pm

Postby CousinItt » Wed Jan 17, 2018 5:53 pm

Shouldn't you be consistent with the spacing in this code? Looks like one macro is parameterised and the other not.

Code: Select all

    PINMODE_OUTPUT_pin_out_1X(1A); // "pin_out_1A" created
    PINMODE_INPUT_pin_in_1X (1B); // "pin_in_1B"  created
User avatar
aclassifier
Respected Member
Posts: 319
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Postby aclassifier » Wed Jan 17, 2018 6:43 pm

CousinItt wrote:Shouldn't you be consistent with the spacing in this code? Looks like one macro is parameterised and the other not.

Code: Select all

    PINMODE_OUTPUT_pin_out_1X(1A); // "pin_out_1A" created
    PINMODE_INPUT_pin_in_1X (1B); // "pin_in_1B"  created


No, that's ok. It COMPILES_FINE. It's in the definition of that macro where spaces aren't accepted:

Code: Select all

#define PINMODE_OUTPUT_pin_out_1X(num) out port pin_out_##num = XS1_PORT_##num // COMPILES
#define PINMODE_OUTPUT_pin_out_1X (num) out port pin_out_##num = XS1_PORT_##num // WILL NOT COMPILE


But thanks anyway, it didn't look nice!
User avatar
aclassifier
Respected Member
Posts: 319
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Postby aclassifier » Wed Jan 17, 2018 9:06 pm

I have made the macros more general, but there is the same problem when COMPILES_FINE is commented away:

Code: Select all

#include <xs1.h>
#include <stdint.h> // uint8_t

typedef enum {LOW,HIGH}   pinval_t; // 0,1

#define XS1_PINMODE_OUTPUT(ID,WIDTH,NUM) out port p##WIDTH##_out_##ID = XS1_PORT_##WIDTH##NUM // Usage global only
//      Examples:
//          XS1_PINMODE_OUTPUT(13,1,A); // p1_out_13 created on XS1_PORT_1A
//          XS1_PINMODE_OUTPUT(13,4,A); // p4_out_13 created on XS1_PORT_4A
//
#define XS1_PINMODE_INPUT(ID,WIDTH,NUM) in port p##WIDTH##_in_##ID = XS1_PORT_##WIDTH##NUM // Usage global only
//      Examples:
//          XS1_PINMODE_INPUT(7,1,B); // "p1_in_7" created on XS1_PORT_1B
//          XS1_PINMODE_INPUT(7,4,B); // "p4_in_7" created on XS1_PORT_4B

void digitalWrite (out port pin, const pinval_t pinval) {
    pin <: pinval;
}

pinval_t digitalRead (in port pin) {
    pinval_t pinval;
    pin :> pinval;
    return pinval;
}

#define PIN_LED    13 // Would have liked to use it also when COMPILES_FINE
#define PIN_BUTTON  7 // Would have liked to use it also when COMPILES_FINE

#define COMPILES_FINE

#ifdef COMPILES_FINE
    // pinMode(13,OUTPUT) // Arduino
    XS1_PINMODE_OUTPUT (13,1,A); // p1_out_13 created on XS1_PORT_1A

    // pinMode(7,INPUT) // Arduino
    XS1_PINMODE_INPUT (7,1,B);   // "p1_in_7" created on XS1_PORT_1B
#else
    #define PORT_WIDTH_BITS  1
    #define PIN_LED_A        A
    #define PIN_BUTTON_B     B
   
    XS1_PINMODE_OUTPUT (PIN_LED,   PORT_WIDTH_BITS, PIN_LED_A);    // error: use of undeclared identifer `XS1_PORT_PORT_WIDTH_BITSPIN_LED_A'
    XS1_PINMODE_INPUT  (PIN_BUTTON,PORT_WIDTH_BITS, PIN_BUTTON_B); // error: use of undeclared identifer `XS1_PORT_PORT_WIDTH_BITSPIN_BUTTON_B'
#endif

int main() {
    pinval_t pinval;
                                      // In __arduino_on_xmos_test.xc.o:
    pinval = digitalRead (p1_in_7);   // note: object used here
                                      // error: call to `digitalWrite' in `main' makes alias of global 'p1_out_13'
    digitalWrite (p1_out_13, pinval); // error: call to `digitalRead' in `main' makes alias of global 'p1_in_7'
   
    return 0;
}
robertxmos
XCore Addict
Posts: 169
Joined: Fri Oct 23, 2015 10:23 am

Postby robertxmos » Thu Jan 18, 2018 12:01 pm

Hi aclassifier

You need to delay concatenation until after any macro expansion has finished.

As you only have a single level of macro expansion:
#define PIN_13_LED 1A

You only need to delay (create an intermediate macro) for one step:
#define GLUE(x,y) x##y
#define PINMODE_OUTPUT_pin_out_1X(num) out GLUE(port pin_out_,num) = GLUE(XS1_PORT_,num)

Now:
PINMODE_OUTPUT_pin_out_1X( PIN_13_LED);
produces:
out port pin_out_1A = XS1_PORT_1A;
User avatar
aclassifier
Respected Member
Posts: 319
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Postby aclassifier » Thu Jan 18, 2018 1:42 pm

Thanks a lot, Robert!

I was looking at an example in some old code of mine (IAR compiler) that had that intermediate step, but I didn't see the forest for the trees. I thought it was for readability, so no bell rang! I must have battled the same ten years ago!

I need the intermediate step when I call the macro with other macros as parameters. In my humble opinion, why does the C preprocessor behave like that? The syntax is fine for both cases, the readability is, but the inner working needs to be held by the hand (or I, the user..). Hmm?

Here is the new code now (have changed naming convention again..). It compiles!

-> Another question, how should I relate to the aliasing errors in the .o file? The code downloads to target. I really haven't looked into the .o file before, so I wouldn't know how aliasing errors would be in those. My makefile is at the bottom.

Code: Select all

/*
#include <xs1.h>
#include <stdint.h> // uint8_t

// -------------------------------
// --       LIBRARY CODE        --
// -------------------------------

// BOOLEAN #include <stdbool.h> if C99
typedef enum {false,true} bool;  // 0,1
typedef enum {LOW,HIGH}   val_t; // 0,1

#define CAT3(a,b,c)   a##b##c
#define CAT4(a,b,c,d) a##b##c##d

#define XS1_PINMODE_OUTPUT(ID,WIDTH,LETTER) out CAT4(port p,WIDTH,_out_,ID) = CAT3(XS1_PORT_,WIDTH,LETTER) // Usage global only
//      out port p1_out_13 = XS1_PORT_1A
//                1     13            1A
//                |     ||            |LETTER
//                WIDTH ID            WIDTH
//
//      Examples:
//          XS1_PINMODE_OUTPUT(13,1,A); // p1_out_13 created on XS1_PORT_1A
//          XS1_PINMODE_OUTPUT(13,4,A); // p4_out_13 created on XS1_PORT_4A
//
#define XS1_PINMODE_INPUT(ID,WIDTH,LETTER) in CAT4(port p,WIDTH,_in_,ID) = CAT3(XS1_PORT_,WIDTH,LETTER) // Usage global only
//      Examples:
//          XS1_PINMODE_INPUT(7,1,B); // "p1_in_7" created on XS1_PORT_1B
//          XS1_PINMODE_INPUT(7,4,B); // "p4_in_7" created on XS1_PORT_4B
//
//     pinMode(12,INPUT_PULLUP) // Arduino, not implemented here

#define XS2_PINMODE_OUTPUT(ID,WIDTH,LETTER) out CAT4(port p,WIDTH,_out_,ID) = CAT3(XS2_PORT_,WIDTH,LETTER) // Usage global only
#define XS2_PINMODE_INPUT(ID,WIDTH,LETTER)  in  CAT4(port p,WIDTH,_in_, ID) = CAT3(XS2_PORT_,WIDTH,LETTER) // Usage global only

void digitalWrite (out port pin, const val_t val) {
    pin <: val;
}

val_t digitalRead (in port pin) {
    val_t val;
    pin :> val;
    return val;
}

// -------------------------------
// --        USER CODE          --
// -------------------------------

#define LED_ID 13 // Drivers LED when LOW (not significant in this code)
#define BUT_ID  7 // Button input

#define LED_PORT_WIDTH  1
#define LED_PORT_LETTER A
#define BUT_PORT_LETTER B

//  pinMode(13,OUTPUT) // Arduino
XS1_PINMODE_OUTPUT (LED_ID, LED_PORT_WIDTH, LED_PORT_LETTER); // p1_out_13  created on XS1_PORT_1A

//  pinMode(7,INPUT) // Arduino
XS1_PINMODE_INPUT  (BUT_ID, LED_PORT_WIDTH, BUT_PORT_LETTER); // "p1_in_7"  created on XS1_PORT_1B

int main() {

    #define ledPin p1_out_13   // note: expanded from here
    #define inPin  p1_in_7     //  note: expanded from here
   
    val_t val;                 // Exactly..
    val = digitalRead(inPin);  // ..like Arduino
    digitalWrite(ledPin,val);  // ..example
   
                               // In __arduino_on_xmos_test.xc.o there are _several_ of these; but not in console
                               // note: object used here
                               // error: call to `digitalRead' in `main' makes alias of global 'p1_in_7'
                               // error: call to `digitalWrite' in `main' makes alias of global 'p1_out_13'
    return 0;
}


Here the makefile, relating to te aliasing error in the .o file. It's unchanged:

Code: Select all

# The TARGET variable determines what target system the application is
# compiled for. It either refers to an XN file in the source directories
# or a valid argument for the --target option when compiling
TARGET = STARTKIT

# The APP_NAME variable determines the name of the final .xe file. It should
# not include the .xe postfix. If left blank the name will default to
# the project name
APP_NAME = __arduino_on_xmos_test

# The USED_MODULES variable lists other module used by the application.
USED_MODULES =

# The flags passed to xcc when building the application
# You can also set the following to override flags for a particular language:
# XCC_XC_FLAGS, XCC_C_FLAGS, XCC_ASM_FLAGS, XCC_CPP_FLAGS
# If the variable XCC_MAP_FLAGS is set it overrides the flags passed to
# xcc for the final link (mapping) stage.
XCC_FLAGS = -O2 -g

# The XCORE_ARM_PROJECT variable, if set to 1, configures this
# project to create both xCORE and ARM binaries.
XCORE_ARM_PROJECT = 0

# The VERBOSE variable, if set to 1, enables verbose output from the make system.
VERBOSE = 0

XMOS_MAKE_PATH ?= ../..
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
robertxmos
XCore Addict
Posts: 169
Joined: Fri Oct 23, 2015 10:23 am

Postby robertxmos » Thu Jan 18, 2018 3:07 pm

Hi aclassifier,
Could you ask questions that drift from the original subject in a new post - for the benefit of those browsing historic posts.
p.s. I built your example and got no error (alias or otherwise).
User avatar
aclassifier
Respected Member
Posts: 319
Joined: Wed Apr 25, 2012 8:52 pm
Contact:

Postby aclassifier » Thu Jan 18, 2018 4:13 pm

robertxmos wrote:Hi aclassifier,
Could you ask questions that drift from the original subject in a new post - for the benefit of those browsing historic posts.
p.s. I built your example and got no error (alias or otherwise).

See http://www.xcore.com/viewtopic.php?f=26&t=6335

Who is online

Users browsing this forum: No registered users and 37 guests