This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software: TI C/C++ Compiler
I want to write the Registers of an external IC. Therefore the data has to be send on one Pin in a strictly defined order.
To keep things readable I wrote an union for that task.
If I run the method Reg_Comm.setupt_Bitstream() the resulting Bitstreams are different depending on the compiler-opt-lvl I chose.
While using opt-lvl 0 The Bitfiled is filled with the data as expected.
But when I change the opt-lvl to 2 the data inside the Bitfiled is different at many places.
(the Data differes after the call of the private method set_Register_Data() )
I allready tried the followeing things.
- Make the union voaltile
- Make the Bitstream-Array voaltile
- delete the fuctiion set_Register_Data() and write it directly into setup_Bitstream()
None of these steps helped.
Detailed Compiler-settings:
Working:
-v28 -ml -mt --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 -Ooff --opt_for_speed=4
Data-Corruption:
-v28 -ml -mt --cla_support=cla1 --float_support=fpu32 --tmu_support=tmu0 --vcu_support=vcu2 -O2 --opt_for_speed=4
Here is the Code:
//HEADER START HERE #define HIGHEST_REGISTER_NUMBER 0x0C typedef union{ struct { uint32_t P : 1; uint32_t DATA_CRC : 4; uint32_t DATA : 8; uint32_t DATA_S : 1; uint32_t W : 1; uint32_t R : 1; uint32_t ADR_CRC : 4; uint32_t ADR : 7; uint32_t ID : 3; uint32_t CTS : 1; uint32_t ADR_S : 1; }Fct_Grp; struct{ uint32_t P_Bit0 : 1; uint32_t DATA_CRC_Bit0 : 1; uint32_t DATA_CRC_Bit1 : 1; uint32_t DATA_CRC_Bit2 : 1; uint32_t DATA_CRC_Bit3 : 1; uint32_t DATA_Bit0 : 1; uint32_t DATA_Bit1 : 1; uint32_t DATA_Bit2 : 1; uint32_t DATA_Bit3 : 1; uint32_t DATA_Bit4 : 1; uint32_t DATA_Bit5 : 1; uint32_t DATA_Bit6 : 1; uint32_t DATA_Bit7 : 1; uint32_t DATA_S_Bit0 : 1; uint32_t W_Bit0 : 1; uint32_t R_Bit0 : 1; uint32_t ADR_CRC_Bit0 : 1; uint32_t ADR_CRC_Bit1 : 1; uint32_t ADR_CRC_Bit2 : 1; uint32_t ADR_CRC_Bit3 : 1; uint32_t ADR_Bit0 : 1; uint32_t ADR_Bit1 : 1; uint32_t ADR_Bit2 : 1; uint32_t ADR_Bit3 : 1; uint32_t ADR_Bit4 : 1; uint32_t ADR_Bit5 : 1; uint32_t ADR_Bit6 : 1; uint32_t ID_Bit0 : 1; uint32_t ID_Bit1 : 1; uint32_t ID_Bit2 : 1; uint32_t CTS_Bit0 : 1; uint32_t ADR_S_Bit0 : 1; }Bits; uint32_t Hex; }Register_Bitstream; class Reg_Comm{ public: void setup_Bitstream(); Register_Bitstream Bitstream[HIGHEST_REGISTER_NUMBER + 1]; private: void set_Register_Adr(); void set_Register_Data(); }; //HEADER ENDS HERE //CPP START HERE #define ENCDS 0 #define M2S 0x00 #define SELRES 0x03 #define HYS 0x00 #define SELSSI 1 #define CRC6 0 #define NZB 0 #define RPL 0 #define AERR 0 #define FERR 0 #define FCTR 0x0004 #define GRAY 0 #define TMODE 0x00 #define TIMO 0 #define TMA 0 #define TOA 0 #define RATIO 0x00 #define GAIN 0x06 #define SINOFFS 0x00 #define COSOFFS 0x00 #define REFOFFS 0 #define PHASE 0x00 void Reg_Comm::setup_Bitstream(){ set_Register_Adr(); set_Register_Data(); for(int i = HIGHEST_REGISTER_NUMBER; i >= 0x00; i--){ Bitstream[i].Fct_Grp.ADR_S = 1; Bitstream[i].Fct_Grp.CTS = 1; Bitstream[i].Fct_Grp.ID = 0b000; /*Bitstream[i].Fct_Grp.ADR_CRC = calculate_CRC( (uint16_t) Bitstream[i].Fct_Grp.ADR + ( ((uint16_t) Bitstream[i].Fct_Grp.ID) << 7) + ( ((uint16_t) Bitstream[i].Fct_Grp.CTS) << 10) , 11); */ Bitstream[i].Fct_Grp.R = 0; Bitstream[i].Fct_Grp.W = 1; Bitstream[i].Fct_Grp.DATA_S = 1; /*Bitstream[i].Fct_Grp.DATA_CRC = calculate_CRC(Bitstream[i].Fct_Grp.DATA , 8); */ Bitstream[i].Fct_Grp.P = 0; } } void Reg_Comm::set_Register_Adr(){ for(uint16_t i = 0; i <= HIGHEST_REGISTER_NUMBER; i++){ Bitstream[i].Fct_Grp.ADR = i; } } void Reg_Comm::set_Register_Data(){ // the data can be changed just by updating the #define // Register 0x00 Bitstream[0x00].Bits.DATA_Bit7 = ENCDS; Bitstream[0x00].Bits.DATA_Bit5 = (M2S & 0x01) ? 1:0; Bitstream[0x00].Bits.DATA_Bit6= (M2S & 0x02) ? 1:0; Bitstream[0x00].Bits.DATA_Bit0 = (SELRES & 0x01) ? 1:0; Bitstream[0x00].Bits.DATA_Bit1 = (SELRES & 0x02) ? 1:0; Bitstream[0x00].Bits.DATA_Bit2 = (SELRES & 0x04) ? 1:0; Bitstream[0x00].Bits.DATA_Bit3 = (SELRES & 0x08) ? 1:0; Bitstream[0x00].Bits.DATA_Bit4 = (SELRES & 0x10) ? 1:0; // Register 0x01 Bitstream[0x01].Bits.DATA_Bit5 = (HYS & 0x01) ? 1:0; Bitstream[0x01].Bits.DATA_Bit6 = (HYS & 0x02) ? 1:0; Bitstream[0x01].Bits.DATA_Bit7 = (HYS & 0x04) ? 1:0; // Register 0x02 Bitstream[0x02].Bits.DATA_Bit6 = SELSSI; // Register 0x03 Bitstream[0x03].Bits.DATA_Bit7 = CRC6; Bitstream[0x03].Bits.DATA_Bit6 = RPL; Bitstream[0x03].Bits.DATA_Bit1 = AERR; Bitstream[0x03].Bits.DATA_Bit0 = FERR; // Register 0x04 Bitstream[0x04].Fct_Grp.DATA |= (uint16_t) (FCTR & 0x00FF) << 7; // Register 0x05 Bitstream[0x05].Bits.DATA_Bit7 = GRAY; Bitstream[0x05].Bits.DATA_Bit0 = (FCTR & 0x0100) ? 1:0; Bitstream[0x05].Bits.DATA_Bit1 = (FCTR & 0x0200) ? 1:0; Bitstream[0x05].Bits.DATA_Bit2 = (FCTR & 0x0400) ? 1:0; Bitstream[0x05].Bits.DATA_Bit3 = (FCTR & 0x0800) ? 1:0; Bitstream[0x05].Bits.DATA_Bit4 = (FCTR & 0x1000) ? 1:0; Bitstream[0x05].Bits.DATA_Bit5 = (FCTR & 0x2000) ? 1:0; Bitstream[0x05].Bits.DATA_Bit6 = (FCTR & 0x4000) ? 1:0; // Register 0x06 Bitstream[0x06].Bits.DATA_Bit5 = TIMO; Bitstream[0x06].Bits.DATA_Bit1 = (TMODE & 0x01) ? 1:0; Bitstream[0x06].Bits.DATA_Bit2 = (TMODE & 0x02) ? 1:0; Bitstream[0x06].Bits.DATA_Bit3 = (TMODE & 0x04) ? 1:0; Bitstream[0x06].Bits.DATA_Bit0 = TMA; // Register 0x07 Bitstream[0x07].Bits.DATA_Bit3 = TOA; // Register 0x08 Bitstream[0x08].Bits.DATA_Bit4 = (GAIN & 0x01) ? 1:0; Bitstream[0x08].Bits.DATA_Bit5 = (GAIN & 0x02) ? 1:0; Bitstream[0x08].Bits.DATA_Bit6 = (GAIN & 0x04) ? 1:0; Bitstream[0x08].Bits.DATA_Bit7 = (GAIN & 0x08) ? 1:0; Bitstream[0x08].Bits.DATA_Bit0 = (RATIO & 0x01) ? 1:0; Bitstream[0x08].Bits.DATA_Bit1 = (RATIO & 0x02) ? 1:0; Bitstream[0x08].Bits.DATA_Bit2 = (RATIO & 0x04) ? 1:0; Bitstream[0x08].Bits.DATA_Bit3 = (RATIO & 0x08) ? 1:0; // Register 0x09 Bitstream[0x09].Fct_Grp.DATA |= SINOFFS << 7; // Register 0x0A Bitstream[0x0A].Fct_Grp.DATA |= COSOFFS << 7; // Register 0x0B Bitstream[0x0B].Bits.DATA_Bit2 = (PHASE & 0x01) ? 1:0; Bitstream[0x0B].Bits.DATA_Bit3 = (PHASE & 0x02) ? 1:0; Bitstream[0x0B].Bits.DATA_Bit4 = (PHASE & 0x04) ? 1:0; Bitstream[0x0B].Bits.DATA_Bit5 = (PHASE & 0x08) ? 1:0; Bitstream[0x0B].Bits.DATA_Bit6 = (PHASE & 0x10) ? 1:0; Bitstream[0x0B].Bits.DATA_Bit7 = (PHASE & 0x20) ? 1:0; Bitstream[0x0B].Bits.DATA_Bit1 = REFOFFS; Bitstream[0x0B].Bits.DATA_Bit0 = (RATIO & 0x10) ? 1:0; } //CPP ENDS HERE
I added volatile to the Bitstream array ...
volatile Register_Bitstream Bitstream[HIGHEST_REGISTER_NUMBER + 1];
I built with --opt_level=2 (same as -O2). I inspected the assembly code generated by the compiler. I compared it to the assembly generated by building with no optimization and no use of volatile. I inspected the memory accesses in the function Reg_Comm::set_Register_Data. Ignore the stack accesses. Look at the memory accesses for Bitstream. I didn't look at every single one. But I looked at enough to be confident the same memory accesses are occurring in the same order.
Based on that analysis, I conclude that adding that volatile should solve your problem. If it doesn't, then show how the memory access order to Bitstream is different between the builds.
Thanks and regards,
-George
Hello George,
I allready tried to add volatile to the Array delcaration but for me this didn't work.
Looking at the generated assembly Code I also notice many differences in the order.
The private Method set_Register_Data starts with the following code:
-opt 2:
338 Bitstream[0x05].Bits.DATA_Bit7 = GRAY; 0086a3: 8EA4 MOVL XAR0, @XAR4 335 Bitstream[0x04].Fct_Grp.DATA |= (uint16_t) (FCTR & 0x00FF) << 7; 0086a4: 8BA4 MOVL XAR1, @XAR4 340 Bitstream[0x05].Bits.DATA_Bit0 = (FCTR & 0x0100) ? 1:0; 0086a5: C5A4 MOVL XAR7, @XAR4 0086a6: A2BD MOVL *SP++, XAR3 341 Bitstream[0x05].Bits.DATA_Bit1 = (FCTR & 0x0200) ? 1:0; 0086a7: 86A4 MOVL XAR2, @XAR4 302 Bitstream[0x00].Bits.DATA_Bit7 = ENCDS; 0086a8: 18C4EFFF AND *+XAR4[0], #0xefff 342 Bitstream[0x05].Bits.DATA_Bit2 = (FCTR & 0x0400) ? 1:0;
-opt off
000227: 18C4EFFF AND *+XAR4[0], #0xefff 304 Bitstream[0x00].Bits.DATA_Bit5 = (M2S & 0x01) ? 1:0; 000229: 8A42 MOVL XAR4, *-SP[2] 00022a: 18C4FBFF AND *+XAR4[0], #0xfbff 305 Bitstream[0x00].Bits.DATA_Bit6= (M2S & 0x02) ? 1:0; 00022c: 8A42 MOVL XAR4, *-SP[2] 00022d: 18C4F7FF AND *+XAR4[0], #0xf7ff 307 Bitstream[0x00].Bits.DATA_Bit0 = (SELRES & 0x01) ? 1:0; 00022f: 8A42 MOVL XAR4, *-SP[2] 000230: 1AC40020 OR *+XAR4[0], #0x0020 308 Bitstream[0x00].Bits.DATA_Bit1 = (SELRES & 0x02) ? 1:0; 000232: 8A42 MOVL XAR4, *-SP[2] 000233: 1AC40040 OR *+XAR4[0], #0x0040 309 Bitstream[0x00].Bits.DATA_Bit2 = (SELRES & 0x04) ? 1:0; 000235: 8A42 MOVL XAR4, *-SP[2] 000236: 18C4FF7F AND *+XAR4[0], #0xff7f 310 Bitstream[0x00].Bits.DATA_Bit3 = (SELRES & 0x08) ? 1:0; 000238: 8A42 MOVL XAR4, *-SP[2] 000239: 18C4FEFF AND *+XAR4[0], #0xfeff
at -opt off everything is called in the exact way it was coded which is correct.
The added volatile keyword as I understood should force the compiler to stick to the same calling order, but this isn't the case.
However in that Codesegment I don't care about the calling order it's not important.
What the big Problem ist, is that some totally different data inside the Bitfield gets corrupted when the compileroptimisation is activated.
Just for example:
-opt 02 generates the following problem with the data inside Bitstream[7].Fct_Grp.ADR
Here everything is fine:
But when running the next line of assembler Code something goes wrong:
the Data inside Bitstream[7].Fct_Grp.ADR changed from 7 to 0 which clearly isn't the purpose of that line of Code.
More Erros with the ADR inside Bitsreams are accuring and with these errors the external IC is setup wrong and won't work.
I have few to no experience with assambler on your devices and I can't fiure out what is going wrong.
Marcel Kummer said:The added volatile keyword as I understood should force the compiler to stick to the same calling order, but this isn't the case.
The volatile memory accesses occur in the same order as the C source. Instructions that do not perform a volatile memory access, including other memory accesses, can occur in any order. So, when you are considering whether the compiler did it correctly, you have to isolate the analysis strictly to the volatile memory accesses, and ignore all the other instructions. When I do that, I see the same order whether optimization is used or not.
Marcel Kummer said:What the big Problem ist, is that some totally different data inside the Bitfield gets corrupted when the compileroptimisation is activated.
Part of what confuses you, I suspect, is the reordering of the instructions. Look at the source line numbers in your screen shot. 385, 383, 378, and so on. No where close to original source order. The instruction or instructions which follow a C statement is not the full implementation of that statement, but only part of it. That's why you see line 383 show up twice. I realize this is confusing. But it is part of what you have to live with when you step through optimized code.
I cannot explain what happens between those screen shots. Which instruction gets executed? Keep in mind that, due to pipelining, it could be an earlier instruction that your screen shot does not show. I don't know enough details about C2000 to say. If you want to get into this even deeper, then we need to involve some C2000 device experts.
Thanks and regards,
-George