I've found some inconsistent behavior in the C2000 compiler. Here's some example code:
void long_pointer_bug_demo(void)
{
uint32_t address;
volatile uint16_t *ptr;
//First read
address = 0x01080000;
ptr = (volatile uint16_t *)address;
*ptr;
//Second read
ptr = (volatile uint16_t *)(uint32_t)0x01080000;
*ptr;
}
With optimizations off, the two reads give different results. The first one loads 0x01080000 into the ACC, then copies it into XAR4, then reads from that address. The second one loads 0x00080000 into XAR4 as an immediate value, truncating the upper 8 bits of the address. It then reads from the truncated address. Here's the assembly:
FE04 ADDB SP, #4
FF2F0210 MOV ACC, #0x210 << 15
1E42 MOVL *-SP[2], ACC
0642 MOVL ACC, *-SP[2]
1E44 MOVL *-SP[4], ACC
8A44 MOVL XAR4, *-SP[4]
92C4 MOV AL, *+XAR4[0]
8F080000 MOVL XAR4, #0x080000
A844 MOVL *-SP[4], XAR4
8A44 MOVL XAR4, *-SP[4]
92C4 MOV AL, *+XAR4[0]
FE84 SUBB SP, #4
0006 LRETR
At optimization level -O2, both reads are optimized to load the truncated address into XAR4 as an immediate value, then read from the truncated address twice in a row:
8F080000 MOVL XAR4, #0x080000
92C4 MOV AL, *+XAR4[0]
92C4 MOV AL, *+XAR4[0]
0006 LRETR
If I change address to be a parameter of the function instead of a local variable, I get results similar to no optimizations:
8AA9 MOVL XAR4, @ACC
92C4 MOV AL, *+XAR4[0]
8F080000 MOVL XAR4, #0x080000
92C4 MOV AL, *+XAR4[0]
0006 LRETR
The C28x Compiler Guide (spru514) states that a pointer is 22 bits, so I think the truncation is intentional. My question is whether the lack of truncation during conversion from a variable is intentional, or a compiler bug, or whether this is a gray area of the C standard.
I know there are compiler intrinsics for 32-bit address accesses (__read32_*() and __write32_*()), but these are not always convenient. Since the C28x CPU does have a 32-bit data address space (per spru430 section 1.3), I think not truncating is better behavior, but perhaps there's a reason why it must be done.
Thanks,