This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

C 7.5 compiler bug

I tried to submit this via the email to tech support page but it gave me a 500 error.
I have a hard time believing that I am the only person this has happened to, but clearly
this is a compiler bug in Keil 8051 version 7.5 compiler.
I hope that someone can get this to the correct person at Keil.

4747   1          if(chksum != CWORD[0xF800])
4748   1              {
4749   2              cstate=1;
4750   2              }
4751   1          if(chksum != CWORD[0xF900])
4752   1              {
4753   2              cstate=1;
4754   2              }
4755   1          if(chksum != CWORD[0xFA00])
4756   1              {
4757   2              cstate=1;
4758   2              }
4759   1          if(chksum != CWORD[0xFB00])
4760   1              {
4761   2              cstate=1;
4762   2              }
4763   1          if(chksum != CWORD[0xFC00])
4764   1              {
4765   2              cstate=1;
4766   2              }
4767   1          if(chksum != CWORD[0xFd00])
4768   1              {
4769   2              cstate=1;
4770   2              }
4771   1
4772   1          if(chksum != CWORD[0xFE00])
4773   1              {
4774   2              cstate=1;
4775   2              }


                                           ; SOURCE LINE # 4747
0645 90F000            MOV     DPTR,#0F000H <<<<<<<<<<<< should be F800
0648 7800        R     MOV     R0,#LOW chksum
064A E6                MOV     A,@R0
064B FE                MOV     R6,A
064C 08                INC     R0
C51 COMPILER V7.50   MEDBEST040_LCD                                                        10/03/2012 12:30:27 PAGE 300

064D E6                MOV     A,@R0
064E FF                MOV     R7,A
064F 7401              MOV     A,#01H
0651 93                MOVC    A,@A+DPTR
0652 6F                XRL     A,R7
0653 7003              JNZ     ?C1279
0655 E4                CLR     A
0656 93                MOVC    A,@A+DPTR
0657 6E                XRL     A,R6
0658         ?C1279:
0658 6006              JZ      ?C0032
                                           ; SOURCE LINE # 4748
                                           ; SOURCE LINE # 4751
0660 90F200            MOV     DPTR,#0F200H   <<<<<<<<<<<<<<<<<<< should be F900
...
                                           ; SOURCE LINE # 4755
0674 90F400            MOV     DPTR,#0F400H   <<<<<<<<<<<<<<<<<<< should be FA00
...
                                           ; SOURCE LINE # 4759
068F 90F600            MOV     DPTR,#0F600H   <<<<<<<<<<<<<<<<<<< should be FB00
...
                                           ; SOURCE LINE # 4763
06AA 90F800            MOV     DPTR,#0F800H   <<<<<<<<<<<<<<<<<<< should be FC00
...
                                           ; SOURCE LINE # 4767
06BE 90FA00            MOV     DPTR,#0FA00H   <<<<<<<<<<<<<<<<<<< should be FD00
...
                                           ; SOURCE LINE # 4772
06D9 90FC00            MOV     DPTR,#0FC00H   <<<<<<<<<<<<<<<<<<< should be FE00



 While this works.
15430  01          FLSCL=0x01;               // enable flash write/erase
15431  01          PSCTL=0x01;                     // BUGG  NOT 2, which would erase flash, but 1write to flash
15432  01          *write_ptr=CBYTE[0xFA00];
15433  01          PSCTL = 0x00;              // MOVX writes target XRAM
15434  01          FLSCL=0;                // disable flash write


 000C 75B701            MOV     FLSCL,#01H
                                           ; SOURCE LINE # 15431
000F 758F01            MOV     PSCTL,#01H
                                           ; SOURCE LINE # 15432
0012 90FA00            MOV     DPTR,#0FA00H
0015 E4                CLR     A
0016 93                MOVC    A,@A+DPTR
0017 8F82              MOV     DPL,R7
0019 8E83              MOV     DPH,R6
001B F0                MOVX    @DPTR,A
                                           ; SOURCE LINE # 15433
001C E4                CLR     A
001D F58F              MOV     PSCTL,A
                                           ; SOURCE LINE # 15434
001F F5B7              MOV     FLSCL,A

  • No bug. Just another person who thought they understood C pointer arithmetic better than they actually did.

    All your uses of CWORD suffer from the same failure. You believe CWORD[n] would read from CODE space address n. It doesn't, and the documentation even says so.

  • not recalling using CWORD, I looked it up. WHAT A TRAP. It would have made much more sense if it was 'intuitive'. Had I not been in the habit of reading documentation when doing something I have not done for a good while, I would have fallen in the same trap.

    NOW, for a valid point: why did the poster not (double) check the documentation before posting?

    Erik

  • not recalling using CWORD, I looked it up. WHAT A TRAP.

    Well, in all fairness given the way it's used, it couldn't possibly have been any different. Something that can be followed by an [index] and yield a 16-bit word from code memory pretty much has to be a 16-bit pointer, and that means the index can't help but count in two-byte steps.

  • I guess that's why they specifically put a not to say that it is not what you might guess:

    Note:
    *
    The index used with this macro does not represent the memory address of the integer value. To obtain the memory address, you must multiply the index by the size of an integer (2 bytes).

    http://www.keil.com/support/man/docs/c51/c51_cword.htm

  • Just didn't think to look in the docs.. But even the docs are a bit obtuse. :)
    I'm glad to know that Erik wouldn't be immune to the trap either :D

    If I were explaining it it would be something like:

    The index used will be multiplied by 2 and truncated to 16 bits by the compiler, because the index is accessing 16 bit words. To access an arbitrary memory location, you should use an index
    that is the address divided by 2. To access 0xF800 for example, you would use an index of x7C00.

  • I sorely miss the "afterthought edit" from 8052.com here

    Erik

  • that is the address divided by 2. To access 0xF800 for example, you would use an index of x7C00.
    I would code it as

    if(chksum != CWORD[0xF900/2])

    or maybe make a macro (why Keil did not do it like this, I do not inderstand)

    MYCSEG CSEG/2 // not the syntax, but the idea

    Erik

  • That would be clearer for sure.
    I think the reason Keil did not do that is because of the way CWORD is defined.
    I've been trying to figure out a clean macro for it just for grins. most anything other
    than they way they defined it would create a lot more code. As it is, they take the index
    and multiply it by 2 truncate it to 16 bits and then do a MOV DPTR,xxxx

    #define CWORD ((unsigned int volatile code *)0)
    


    since that is a text substitution how would you do it as a macro?

    #define CWORD  ((unsigned int volatile code *)0) /2 would not work.
    

    I guess one could convert it to a function macro with a parameter, something like the code below. Been a long while since I defined a macro with a parameter, so may have the syntax wrong...

    #define CWORD_AT(val) ((unsigned int volatile code *) 0)[val/2]
    

    .. I once asked Brian Kernighan of K&RC fame why they did not use the @ for a pointer, so it
    would verbalize as char at and his comment was essentially, we would have except that the editor we had used the @ as a line deletion command, so there was no way to embed it in the line....

    just a little c history...

  • #define CWORD_AT(val) ((unsigned int volatile code *) 0)[val/2]
    

    That would assume that val is even; ie, that all ints are aligned on even addresses - there is no reason for that to be the case on an 8051!

  • ... that all ints are aligned on even addresses ...

    Much like Keil's original then?

  • Yes - and that one isn't mentioned in the doc!

  • Keils original?
    Hmm. I first used this compiler in the late 1980-early 1990's under the name Franklin C. version 2 if I remember right.
    I don't remember any details, but I do have the installation on a computer so I could find out
    what the original implementation of this was...

    CWORD[0xFA01] will access F402 where FA00 will equal F400, so the macro as it is
    always yields an integer on a even boundary. An yes, this is not necessarily valid on the 8051.

    That is ANOTHER undocumented trap with this macro....
    You SHOULD be able to access 0xF001 and 0xF002 with this macro, but the Keil macro will not let
    you *and* it DOESN'T tell you that in the docs....though that might be inferred from the docs, when it says *2..

    You would have to modify the macro to be a *1, rather than an *0 probably, but I haven't tried that.

  • That is ANOTHER undocumented trap with this macro....
    You SHOULD be able to access 0xF001 and 0xF002 with this macro,

    "SHOULD", shouted? Why that?

    You should be able to do with this macro exactly what its documentation says you should. All that goes beyond that is pie-in-the-sky thinking. As engineers we surely should know better than to engage in such.

    Similarly, we should know better than to expect some magically 100% fool-proof documentation. Nothing is ever fool-proof. If anyone ever comes close to that goal, Nature will just make better fools --- you simply can't beat an opponent like that, with billions of years of experience, on its home turf.