Hello all!
I'm writing to a chip with a cortex m-4 in it and the compiler creates a weird assembly:
I'm trying to develop an I2C driver so i have a made some unions to allow easy access to registers, it all worked fine until today - today things got quite phishy!
take a look:
compiler option:
here is the code for the union of "reg":
typedef union { uint32_t value; struct { unsigned dummy1 :1 unsigned dummy2 :1 . . . unsigned dummy32 :1 }fields; } IC_INTR_MASK; /******************************/ //module typedef typedef struct _MODULE_S { IC_INTR_STAT IC_INTR_STAT; } I2CInitDef;
As you can see the compiler creates the assembly with a "!"(write back to the register) - so after I write 0x00 to "reg->IC_INTR_MASK.value" the pointer of "reg" is no longer point to the right address!
I can tell I'm using this method to write hardware registers all over my code and it always works fine! what do you thing might be the problem here?
Willie said:so after I write 0x00 to "reg->IC_INTR_MASK.value" the pointer of "reg" is no longer point to the right address!
Not really. After that step register r3 no longer holds the pointer variable 'reg'. Whether that's wrong or not can not be seen from the snippet you show. It depends on what happens to r3 next, which you didn't show.
Yes to what Broeker. What you are showing seems to all be OK. What happens next might not be, but there is no indication from what you have shown that the compiler has done something wrong. I can see that R3 contains 0x4004000 before it executes the current instruction. It will contain 0x40004030 afterwards (and that is the address it sets to 0). Just a (very educated) guess but I would be pretty sure that this is the address of the IC_INTR_MASK.
Maybe you think the volatile in the declaration would limit the compilers ability to optimize the value of reg. Well, what you have told the compiler is that what reg points to is volatile, but you have not specified the variable reg itself is volatile so it feels quite free to optimize that and it appears it has. Change the declaration and you probably will see different code generated.
volatile I2CInitDef * volatile reg = (I2CIntDef *) (obj->i2c_address);
My guess is you will find the code generated will seem to make many extra references to a variable on the stack. When you look at the code generated in both cases you can probably convince yourself that they are both "correct", but that making the reg variable volatile when it does not need to be causes extra code to be generated that serves no purpose.
This realy fixed the problem!
thanks!
And how did you convince yourself that there ever was an actual problem to be fixed, in the first place?
I just saw that after the first write into "reg" its address changes, and that means that every other writes into "reg" are in 0x30 offset from its actual start address.
I used the IDE watch to verify it... and then I looked at the assembly to see what is the difference between this write to other writes I do in my code...