Forums

[LPC2104] hardware bug...

Started by Pawel Sikora September 9, 2004
# a simple testcase #

typedef volatile unsigned int reg32;

#define __DECLARE_IO_REG32_BIT(name) \
typedef volatile union { \
name##_bits bit; \
reg32 reg; \
} name##_bits_t

typedef struct {
reg32 MR0INT :1;
reg32 MR0RES :1;
reg32 MR0STOP :1;
reg32 MR1INT :1;
reg32 MR1RES :1;
reg32 MR1STOP :1;
reg32 MR2INT :1;
reg32 MR2RES :1;
reg32 MR2STOP :1;
reg32 MR3INT :1;
reg32 MR3RES :1;
reg32 MR3STOP :1;
reg32 :20;
} __mcr_bits;

__DECLARE_IO_REG32_BIT(__mcr);

#define T0MCR (*(__mcr_bits_t *)0xE0004014)

void test()
{
T0MCR.reg = 0x00000000; // dumpT0MCR -> 0x00000000
/* disassembled code
mov r2, #-536870912
add r2, r2, #16384
add r2, r2, #20
mov r3, #0
str r3, [r2, #0] // r2 == 0xe0004014
*/
#if 0
T0MCR.reg |= 0x01; // dumpT0MCR -> 0x00000001
T0MCR.reg |= 0x02; // dumpT0MCR -> 0x00000003
/* disassembled code
ldr r3, [r2, #0]
orr r3, r3, #1
str r3, [r2, #0]
ldr r3, [r2, #0]
orr r3, r3, #2
str r3, [r2, #0]
*/
#else
T0MCR.bit.MR0INT = 1; // dumpT0MCR -> 0x00000101
T0MCR.bit.MR0RES = 1; // dumpT0MCR -> 0x00000303
/* disassembled code
ldrb r3, [r2, #0]
orr r3, r3, #1
strb r3, [r2, #0]
ldrb r3, [r2, #0]
orr r3, r3, #2
strb r3, [r2, #0]
*/
#endif
}

# possible STRB behaviour (tested with T0MCR and T0IR)
#

[address][7:0] = Rn[7:0]
[address][15:8]= Rn[7:0]

Could anyone confirm this?

__________________________________




An Engineer's Guide to the LPC2100 Series

Pawel,

> # a simple testcase #
>
> typedef volatile unsigned int reg32;
>
> #define __DECLARE_IO_REG32_BIT(name) \
> typedef volatile union { \
> name##_bits bit; \
> reg32 reg; \
> } name##_bits_t
>
> typedef struct {
> reg32 MR0INT :1;
> reg32 MR0RES :1;
> reg32 MR0STOP :1;
> reg32 MR1INT :1;
> reg32 MR1RES :1;
> reg32 MR1STOP :1;
> reg32 MR2INT :1;
> reg32 MR2RES :1;
> reg32 MR2STOP :1;
> reg32 MR3INT :1;
> reg32 MR3RES :1;
> reg32 MR3STOP :1;
> reg32 :20;
> } __mcr_bits;
>
> __DECLARE_IO_REG32_BIT(__mcr);
>
> #define T0MCR (*(__mcr_bits_t *)0xE0004014)
>
> void test()
> {
> T0MCR.reg = 0x00000000; // dumpT0MCR -> 0x00000000
> /* disassembled code
> mov r2, #-536870912
> add r2, r2, #16384
> add r2, r2, #20
> mov r3, #0
> str r3, [r2, #0] // r2 == 0xe0004014
> */
> #if 0
> T0MCR.reg |= 0x01; // dumpT0MCR -> 0x00000001
> T0MCR.reg |= 0x02; // dumpT0MCR -> 0x00000003
> /* disassembled code
> ldr r3, [r2, #0]
> orr r3, r3, #1
> str r3, [r2, #0]
> ldr r3, [r2, #0]
> orr r3, r3, #2
> str r3, [r2, #0]
> */
> #else
> T0MCR.bit.MR0INT = 1; // dumpT0MCR -> 0x00000101
> T0MCR.bit.MR0RES = 1; // dumpT0MCR -> 0x00000303
> /* disassembled code
> ldrb r3, [r2, #0]
> orr r3, r3, #1
> strb r3, [r2, #0]
> ldrb r3, [r2, #0]
> orr r3, r3, #2
> strb r3, [r2, #0]
> */
> #endif
> }
>
> # possible STRB behaviour (tested with T0MCR and T0IR) #
>
> [address][7:0] = Rn[7:0]
> [address][15:8]= Rn[7:0]
>
> Could anyone confirm this?

Combination of compiler and ARM is your problem. The registers need to
be accessed as 32-bit data, they can't be accessed as byte-wise data.
Hence, the LDRB and STRB are not correct for the peripheral registers.
How you convince GCC to generate word accesses in this case, I'm not
sure, but it's got more options than a nuclear power station, so there
must be one somewhere to say "don't narrow".

-- Paul.


> > typedef struct {
> > reg32 MR0INT :1;
> > reg32 MR0RES :1;
> > reg32 MR0STOP :1;
> > reg32 MR1INT :1;
> > reg32 MR1RES :1;
> > reg32 MR1STOP :1;
> > reg32 MR2INT :1;
> > reg32 MR2RES :1;
> > reg32 MR2STOP :1;
> > reg32 MR3INT :1;
> > reg32 MR3RES :1;
> > reg32 MR3STOP :1;
> > reg32 :20;
> > } __mcr_bits;

The problem here is that gcc for bit field access will generate 8/16/32 bits
access depending on the width of the bit field. This is allowed for memory
based operations if the memeory accepts 8/1/632 bit transfers (most
configurations do), but deadly in case of I/O registers that can only be
written 32 bits at a time.

We have seen large projects where the original sources with I/O as bitfields
(ADS or Greenhills compiler) were all rewritten into macro's for use with
the GCC toolchain.
We also stay safely with that method ;-)

Regards,
Arie de Muynck