Hi!
The interesting thing is something different:
While ADC12CTL0 is defined as volatile unsigned int, why dows the compiler read
it in two parts? It SHOULD read it with a word instruction into a register no
matter where it is located (whether 16bit I/O space or
anywhere else) as it could be modified in an ISR (or by hardware) between the
two byte accesses.
I think the reason is that the very strange construct to return and typecast
the content of ADC12CTL0 causes the compiler to forget about the volatile type
of the source.
&ADC12CTL0 resolves to a pointer to a volatile unsigned int which is then
typecasted to a pointer to a adc12ctl0_t structure. In this conversion it loses
all information about being volatile. It's just a plain vanilla pointer
pointing to something to be interpreted as an adc12ctl0_t structure. In the
following steps, the compiler does what it would do with any other normal
pointer.
If I compiler the below example, I get a
ez3.c: In function `getCtl0':
ez3.c:45: warning: cast discards qualifiers from pointer target type
So the compiler tells you that there's something going possibly wrong. And it
does. And this is not the compilers fault.
I'd say it is not a compiler bug but a programmer bug.
return (adc12ctl0_t) ADC12CTL0;
should do better. And should be much faster. But fails due to the incompatible
type of data (non-scalar struct and scalar word value). This is also the reason
why the compiler does not use a word instruction for
constructing the result: the target is not a scalar type. And it has been
packed, so it cannot be assumed word-aligned at all. The compiler does not know
that in this special case it could just transfer a source word to
a target word-size structure. It just assembles the target, and it does so
(unoptimized) field by field, using the source only byte-wise. even after
optimisation, when the optimisation algorithm discovers that the bit-wise
assembly is unnecessary, the byte-wise source access still remains, as the
optimisation does not know that it could be put together again. It does not
even know for sure whether the target is word-aligned. Only the
linker can tell.
Even faster and way more logical would be:
volatile adc12ctl0_t ctl0 __asm ("0x01A0");
no inline function, no function call, just a volatile word-sized struct placed
somewhere in memory. But here again the compiler must fail due to the packed
non-scalar type.
Handling this very special problem by type conversion is simply not in the
range of the C language. You must give the compiler additional help here.
There are two possible solutions: either you program the inlince code in direct
assembly (by just loading the ADC12CTL0 into R14) or tell the compiler to use
an intermediate storage place.
adc12ctl0_t getCtl0(void )
{
int i = ADC12CTL0;
return * (adc12ctl0_t *)&i;
}
This results into
212 0000 0512 push r5
213 0002 0412 push r4
214 0004 0541 mov r1, r5
215 0006 3550 0600 add #6, r5
216 000a 2183 sub #2, r1 ; 2, fpn 1
217 000c 0441 mov r1,r4
223 000e 9442 A001 mov &0x01A0, @r4
226 0014 0E43 mov #llo(0), r14
227 0016 6F44 mov.b @r4, r15
228 0018 7FF3 and.b #-1, r15
229 001a 3EF0 00FF and #0xff00, r14
230 001e 0EDF bis r15, r14
231 0020 5F44 0100 mov.b 1(r4), r15
232 0024 7FF3 and.b #-1, r15
233 0026 8F10 swpb r15
234 0028 7EF3 and.b #-1, r14
235 002a 0EDF bis r15, r14
236 002c 0F4E mov r14, r15
242 002e 2153 add #2, r1
243 0030 3441 pop r4
244 0032 3541 pop r5
245 0034 3041 ret
Which is still big and bloadted but at least correct.
With optimisation -Os you'll get the smaller, but still unnecessary big
212 0000 2183 sub #2, r1 ; 2, fpn 0
218 0002 9142 A001 mov &0x01A0, @r1
221 0008 6E41 mov.b @r1, r14
222 000a 5F41 0100 mov.b 1(r1), r15
223 000e 8F10 swpb r15
227 0010 0FDE bis r14, r15
230 0012 2153 add #2, r1
231 0014 3041 ret
The same result (but even without optimisation) gives
static inline adc12ctl0_t getCtl0(void )
{
adc12ctl0_t i;
__asm__ __volatile__ ("mov.w %1,%0":"=m"(i):"m"(ADC12CTL0));
return i;
}
If you want it really short, just define a macro that resolves into an inline
assembly code for the transfer:
#define getCtl0(dest) __asm__ __volatile__ ("mov.w
%1,%0":"=m"(dest):"m"(ADC12CTL0))
it simply compiles to
222 0000 9242 A001 mov.w &0x01A0,&dest
what is what you want, but requires "dest" to be word-aligned else the result
will be unpredictable. And of course it will not resolve to a value and
therefore cannot be used in assignments or calculations.
If you remove the packed attribute from the struct, the inline function with
ASM code gives (with -Os):
218 0000 2183 sub #2, r1 ; 2, fpn 0
228 0002 9142 A001 mov.w &0x01A0,@r1
234 0008 A241 0000 mov @r1, &dest
239 000c 2153 add #2, r1
and it will ensure that dest is always word-aligned in memory (except you do
some more pointer typecasting or include the struct into other packed structs).
JMGross
----- Ursprüngliche Nachricht -----
Von: Rohit Pagariya
An: GCC for MSP430 - http://mspgcc.sf.net
Gesendet am: 14 Okt 2009 01:28:15
Betreff: [Mspgcc-users] Compiler Bug Report: Read of registers in peripheral
address space
I don't if this bug has been already reported, I couldn't find a bug
report. So here goes:
The latest version of mspgcc3 (I built it on October 11) has a bug which
affects the ADC12 operation.
The specification says : The address space from 0100 to 01FFh is
reserved for 16-bit peripheral modules. These modules should be accessed
with word instructions. If byte instructions are used, only even
addresses are permissible, and the high byte of the result is always 0.
Thus byte reads at odd addresses are not permissible and the result is
unpredictable.
For the following ADC related function in TinyOS 2.1,
typedef struct __nesc_unnamed4254 {
volatile unsigned
adc12sc : 1,
enc : 1,
adc12tovie : 1,
adc12ovie : 1,
adc12on : 1,
refon : 1,
r2_5v : 1,
msc : 1,
sht0 : 4,
sht1 : 4;
} __attribute((packed)) adc12ctl0_t;
volatile unsigned int ADC12CTL0 __asm ("0x01A0");
static inline adc12ctl0_t getCtl0(void )
{
return * (adc12ctl0_t *)&ADC12CTL0;
}
The assembly produced at -O0 for msp430F1611 is
<getCtl0>:
push r5
push r4
clr r14
mov.b &0x01a0,r15
and.b #-1, r15 ;r3 As==11
and #-256, r14 ;#0xff00
bis r15, r14
mov.b &0x01a1,r15 /* A byte read at an odd address in the
peripheral address space is not permitted. */*
and.b #-1, r15 ;r3 As==11
swpb r15
and.b #-1, r14 ;r3 As==11
bis r15, r14
mov r14, r15
pop r4
pop r5
ret
This bug is present at all levels of optimization. Has anyone else run
into this bug as well?
Rohit
------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Mspgcc-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mspgcc-users