[U-Boot-Users] possible ELDK4 gcc compiler bug

Hi,
I noticed some strange behavior when using the ELDK4 gcc for compiling U-Boot for a (new) 405 target based on the current PMC405 board.
The code needs to read-modify-write a memory mapped FPGA internal register. But the FPGA access does not appear in the object and therefore it is never done.
Here are some code snippets:
1) my 'fifo' BSP command:
int do_fifo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { struct pmc405v2_fpga_s *fpga = (struct pmc405v2_fpga_s *)FPGA_BA; int i; int n = 0; u32 ctrl, data, f; char str[] = "\|/-"; int abort = 0; int count = 0; int count2 = 0;
switch(argc) { case 2: /* completely read out fifo 'n' */ if (!strcmp(argv[1],"read")) { printf(" # fifo level data\n"); printf("__________________________________\n");
for (i=0; i<FIFO_COUNT; i++) { dump_fifo(fpga, i, &n); } } else if (!strcmp(argv[1],"wait")) { got_fifoirq = 0;
irq_install_handler (FPGA_IRQ, (interrupt_handler_t *)fpga_interrupt, (void*)fpga);
printf(" # fifo level data\n"); printf("__________________________________\n");
fpga->ctrl |= CTRL_FIFO_IE; for (i=0; i<FIFO_COUNT; i++) { /* enable interrupts from all fifos */ printf("DEBUG1: %p:%08x\n", &(fpga->fifo[i].ctrl), fpga->fifo[i].ctrl); --> These RMW-ops do not appear in the object and is never done! --> fpga->fifo[i].ctrl |= 0x8000; printf("DEBUG2: %p:%08x\n", &(fpga->fifo[i].ctrl), fpga->fifo[i].ctrl); }
while (1) { /* wait loop */ while(!got_fifoirq) { ...
2) Here are the used structs for the fpga variable: struct pmc405v2_fifo_s { volatile u32 data; volatile u32 ctrl; };
/* fifo ctrl register */ #define FIFO_OVERFLOW 0x00000400 #define FIFO_EMPTY 0x00000200 #define FIFO_FULL 0x00000100 #define FIFO_IE 0x00008000 #define FIFO_LEVEL_MASK 0x000000ff
#define FIFO_COUNT 4
struct pmc405v2_fpga_s { volatile u32 ctrl; volatile u32 status; volatile u32 test1; volatile u32 test2; u32 pad1[0x60 / sizeof(u32) - 4]; volatile u32 hostctrl; /* 0x0060 */ u32 pad2[0x20 / sizeof(u32) - 1]; struct pmc405v2_fifo_s fifo[FIFO_COUNT]; /* 0x0080..0x009f */ };
3) Here are some lines from the objectdump. I do not find anything from the RMW-op to the FPGA register (fpga->fifo[i].ctrl |= 0x8000;).
/data/home/matthias/projects/pmc405/V2_u-boot.git/board/esd/pmc405v2/cmd_pmc405v2.c:556 dd8: 48 00 00 01 bl dd8 <do_fifo+0x178> dd8: R_PPC_PLTREL24 printf /data/home/matthias/projects/pmc405/V2_u-boot.git/board/esd/pmc405v2/cmd_pmc405v2.c:558 ddc: 3d 20 ef 00 lis r9,-4352 de0: 80 09 00 00 lwz r0,0(r9) de4: 3b 40 00 00 li r26,0 de8: 60 00 02 00 ori r0,r0,512 dec: 90 09 00 00 stw r0,0(r9) df0: 7f 7f db 78 mr r31,r27 /data/home/matthias/projects/pmc405/V2_u-boot.git/board/esd/pmc405v2/cmd_pmc405v2.c:561 for (i=0; i<FIFO_COUNT; i++) { /* enable interrupts from all fifos */ printf("DEBUG1: %p:%08x\n", df4: 83 9b 00 00 lwz r28,0(r27) df8: 80 7e 80 cc lwz r3,-32564(r30) dfc: 7f e4 fb 78 mr r4,r31 e00: 7f 85 e3 78 mr r5,r28 e04: 48 00 00 01 bl e04 <do_fifo+0x1a4> e04: R_PPC_PLTREL24 printf /data/home/matthias/projects/pmc405/V2_u-boot.git/board/esd/pmc405v2/cmd_pmc405v2.c:564 &(fpga->fifo[i].ctrl), fpga->fifo[i].ctrl); fpga->fifo[i].ctrl |= 0x8000; printf("DEBUG2: %p:%08x\n", e08: 80 7e 80 d0 lwz r3,-32560(r30) e0c: 7f e4 fb 78 mr r4,r31 e10: 7f 85 e3 78 mr r5,r28 e14: 48 00 00 01 bl e14 <do_fifo+0x1b4> e14: R_PPC_PLTREL24 printf /data/home/matthias/projects/pmc405/V2_u-boot.git/board/esd/pmc405v2/cmd_pmc405v2.c:559 e18: 2f 9a 00 03 cmpwi cr7,r26,3 e1c: 3b ff 00 08 addi r31,r31,8 e20: 3b 7b 00 08 addi r27,r27,8 e24: 3b 5a 00 01 addi r26,r26,1 e28: 40 9e ff cc bne+ cr7,df4 <do_fifo+0x194> e2c: 3b e0 00 00 li r31,0 e30: 48 00 00 6c b e9c <do_fifo+0x23c> /data/home/matthias/projects/pmc405/V2_u-boot.git/board/esd/pmc405v2/cmd_pmc405v2.c:571 &(fpga->fifo[i].ctrl), fpga->fifo[i].ctrl); }
while (1) { /* wait loop */ while(!got_fifoirq) { count++; e34: 3b ff 00 01 addi r31,r31,1 /data/home/matthias/projects/pmc405/V2_u-boot.git/board/esd/pmc405v2/cmd_pmc405v2.c:572
4) This is how the compiler is called for the code file: ppc_4xx-gcc -g -Os -fPIC -ffixed-r14 -meabi -fno-strict-aliasing -D__KERNEL__ -DTEXT_BASE=0xFFF80000 -I/data/home/matthias/projects/pmc405/V2_u-boot.git/include -fno-builtin -ffreestanding -nostdinc -isystem /opt/eldk_400/usr/bin/../lib/gcc/powerpc-linux/4.0.0/include -pipe -DCONFIG_PPC -D__powerpc__ -DCONFIG_4xx -ffixed-r2 -ffixed-r29 -mstring -Wa,-m405 -mcpu=405 -msoft-float -Wall -Wstrict-prototypes -c -o cmd_pmc405v2.o cmd_pmc405v2.c
Any idea about what I am doing wrong?
BTW: Using -O0 instead of -Os makes everything fine - at least for the code above.
Matthias

On Thursday 07 December 2006 17:21, Matthias Fuchs wrote:
int do_fifo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { struct pmc405v2_fpga_s *fpga = (struct pmc405v2_fpga_s *)FPGA_BA;
Making 'fpga' static solves the problem. But why?
Matthias

On 07 Δεκ 2006, at 11:28 ΠΜ, Matthias Fuchs wrote:
On Thursday 07 December 2006 17:21, Matthias Fuchs wrote:
int do_fifo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { struct pmc405v2_fpga_s *fpga = (struct pmc405v2_fpga_s *)FPGA_BA;
Making 'fpga' static solves the problem. But why?
You are getting hit by the optimizer, even getting this far was lucky.
Just for kicks, try:
volatile struct pmc405v2_fpga_s *fpga = (volatile struct pmc405v2_fpga_s *)FPGA_BA;
But you should really be using accessors...
Pantelis
Matthias
--
Dipl.-Ing. Matthias Fuchs esd electronic system design gmbh http://www.esd-electronics.com Vahrenwalder Str. 207 phone: +49-511-37298-0, fax: -68 30165 Hannover, Germany
Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php? page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ U-Boot-Users mailing list U-Boot-Users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/u-boot-users

On Thursday 07 December 2006 17:38, Pantelis Antoniou wrote:
But you should really be using accessors...
You might be right, but I really like to lay a struct over a IO-controllers registers.
Do so with accessors result in code like this (still missing some casts):
out32(&(fpga->fifo[i].ctrl), in32(&(fpga->fifo[i].ctrl)) | 0x8000);
Is this really recommended?
For simple IO operations
out32(FPGA_FIFO_CTRL, in32(FPGA_FIFO_CTRL) | 0x8000);
is fine. But with a more complex register layout like this:
struct pmc405v2_fpga_s { volatile u32 ctrl; volatile u32 status; volatile u32 test1; volatile u32 test2; u32 pad1[0x60 / sizeof(u32) - 4]; volatile u32 hostctrl; /* 0x0060 */ u32 pad2[0x20 / sizeof(u32) - 1]; struct pmc405v2_fifo_s fifo[FIFO_COUNT]; /* 0x0080..0x009f */ };
It results in ugly code.
Matthias

Matthias Fuchs wrote:
Do so with accessors result in code like this (still missing some casts):
out32(&(fpga->fifo[i].ctrl), in32(&(fpga->fifo[i].ctrl)) | 0x8000);
Is this really recommended?
That's how I would do it. You could use a temporary variable:
u32 ctrl;
ctrl = in32(&(fpga->fifo[i].ctrl)); out32(&(fpga->fifo[i].ctrl), ctrl | 0x8000);

On 07 Δεκ 2006, at 12:25 ΜΜ, Timur Tabi wrote:
Matthias Fuchs wrote:
Do so with accessors result in code like this (still missing some casts): out32(&(fpga->fifo[i].ctrl), in32(&(fpga->fifo[i].ctrl)) | 0x8000); Is this really recommended?
That's how I would do it. You could use a temporary variable:
u32 ctrl;
ctrl = in32(&(fpga->fifo[i].ctrl)); out32(&(fpga->fifo[i].ctrl), ctrl | 0x8000);
-- Timur Tabi Linux Kernel Developer @ Freescale
#define FPGA_SETBITS(f, m, v) \ out32(&(f)->m, in32(&(f)->m | (v))
FPGA_SET_BITS(fifo[i].ctrl, 0x8000)
Knock yourself out.
Pantelis

-----Original Message----- From: Matthias Fuchs *)FPGA_BA; Making 'fpga' static solves the problem. But why?
Making it volatile will solve it.
The reason is that the ctrl member is not used anywhere else (except for some printf's) sothe compiler just strores the value in a register an optimizes away the access to the datastructure (and your hardware). By making it volatile, you force the compiler to never optimize away the accesses.
BTW. your original code would probably have worked with -O0 optimizattion level.

On Thursday 07 December 2006 17:42, Rune Torgersen wrote:
-----Original Message----- From: Matthias Fuchs *)FPGA_BA; Making 'fpga' static solves the problem. But why?
Making it volatile will solve it.
I tried that - of course. But it didn't solve the problem.
The reason is that the ctrl member is not used anywhere else (except for some printf's) sothe compiler just strores the value in a register an optimizes away the access to the datastructure (and your hardware). By making it volatile, you force the compiler to never optimize away the accesses.
BTW. your original code would probably have worked with -O0 optimizattion level.
Yes, it does.
Matthias

On 07 Δεκ 2006, at 11:21 ΠΜ, Matthias Fuchs wrote:
Hi,
[snip]
Declare your struct variable pointer as volatile.
The compiler optimizes all your accesses away.
Even volatile is considered bad form nowadays, the proper one is using accessors which do the _right_ thing for your specific hardware.
Regards
Pantelis

Matthias Fuchs wrote:
Hi,
I noticed some strange behavior when using the ELDK4 gcc for compiling U-Boot for a (new) 405 target based on the current PMC405 board.
The code needs to read-modify-write a memory mapped FPGA internal register. But the FPGA access does not appear in the object and therefore it is never done.
Here are some code snippets:
- my 'fifo' BSP command:
int do_fifo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { struct pmc405v2_fpga_s *fpga = (struct pmc405v2_fpga_s *)FPGA_BA; int i; int n = 0;
The compiler is optimizing away your code. Check out the 'volatile' keyword. It is exactly this situation it was intended. A better way is to use in32() out32() etc. The I/O accessors make sure I/O operation is completed before next instruction is executed. Simply accessing the memory mapped registers might not archive the same.
Best regards, Tolunay
participants (5)
-
Matthias Fuchs
-
Pantelis Antoniou
-
Rune Torgersen
-
Timur Tabi
-
Tolunay Orkun