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

NOP Vs _nop_()?

In one of my project I am talking with MX909 Driver IC with C51 ucontroller. To initialize MX909 if I write module in Assembly language it's working fine. Once I replaced with C same module it's not working.

The only difference I can make for both assembly and C languages is NOP and _nop_() instruction. Is both instructions will take same number of machine cycles?

Thanks,
Suresh Kumar Kavula

  • Once I replaced with C same module
    why on earth did you do that?

    The only difference I can make for both assembly and C languages is NOP and _nop_() instruction. Is both instructions will take same number of machine cycles?

    If you had taken one second to look at the generated assembly you would have found that they are identical.

    My guess is that you suffer from some fallacy that e.g. a for loop is the same as a djnz loop and nothing could be farther from the truth.

    If you, for some silly reason, have to "replace with C" have a look at the assembler code generated by the compiler and you will find your answer.

    Erik

  • Erik,

    Thanks for your quick response. By using keil C I am trying to generate 2.4uSeconds delay by writing 4 _nop_() instructions. For this I am using I am using AT89C5131, X1 clock Mode with 20 MHZ.

    Same C routine if I replace 4 NOP instructions by using #pragma ASM working fine.

    I don't know what the reason is.

    Thanks,
    Suresh Kumar Kavula

  • ONCE MORE

    LOOK AT THE ASM GENERATED BY THE COMPILER!!

    Erik

  • Yes, disassembly generating NOP instructions only for each _nop_() instruction.

    It seems problem in some where else.

    Thanks a lot Erik for your help.

  • Yes, disassembly

    That is just too cumbersome a method, why not use the .lst file?. Or to be real fancy do a 'test compile' with #pragma SRC

    Erik

  • "Yes, disassembly generating NOP instructions only for each _nop_() instruction"

    I should hope so too - that's exactly what it is defined to do: http://www.keil.com/support/man/docs/c51/c51__nop_.htm

    However, this is where any code-generation guarantee ends!

    It is fundamental to the nature of High-Level Languages (HLLs; including 'C') that you have absolutely no control whatsoever over the code that will be generated by the compiler.

    Therefore, although the _nop_() Intrinsic Function is guaranteed to insert a single NOP instruction, you have absolutely no control whatsoever over the rest of the code that will be generated around the _nop_() "call".

    Therefore, you must use an assembler routine if you need a predictable delay!

  • Or to be real fancy do a 'test compile' with #pragma SRC

    I'd advise extra care with that approach. There's no guaranteed whatsoever that the code output in #pragma SRC mode is the same as otherwise.

    The only reliable ways to find out what the compiler did are the list file, absolute list file (if linker optimizations are enabled) and disassembler/debugger views.

  • "There's no guaranteed whatsoever that the code output in #pragma SRC mode is the same as otherwise."

    There is also no guarantee whatsoever that the results will remain the same on subsequent re-compiles!

    How many times does "no guarantee whatsoever" have to be said make the point that this is a bad idea...?

  • Andy,

    I'm going to have to make a favourite of that one!

    Thanks.

  • My guess is that you suffer from some fallacy that e.g. a for loop is the same as a djnz loop and nothing could be farther from the truth.

    ----- FUNCTION main (BEGIN) -----
        8: void main(void)
        9: {
       10:    unsigned char loop;
       11:
       12:    for(loop=128;loop;loop--)
    ;---- Variable 'loop' assigned to Register 'R7' ----
    00000F 7F80              MOV     R7,#080H
    000011         ?C0001?TEST:
       13:    {
       14:    }
    000011 DFFE              DJNZ    R7,?C0001?TEST
    000013         ?C0004?TEST:
       15:
       16:    while(1);
    000013 80FE              SJMP    ?C0004?TEST
    ----- FUNCTION main (END) -------
    

  • My guess is that you suffer from some fallacy that e.g. a for loop is the same as a djnz loop and nothing could be farther from the truth.

    Jack,

    The authoritative masquerade very clearly exposed!

  • The compiler may implement a for loop by using a djnz.

    And here's proof that a for loop is not the same as a djnz loop:

    line level    source
    
       1          int main(void)
       2          {
       3   1              unsigned char loop;
       4   1
       5   1              for(loop = 0; loop != 128; loop++)
       6   1              {
       7   2              }
       8   1              while(1);
       9   1              return(0);
      10   1      }
    C51 COMPILER V8.02   MAIN                                                                  08/15/2007 13:01:31 PAGE 2
    
    ASSEMBLY LISTING OF GENERATED OBJECT CODE
    
    
                 ; FUNCTION main (BEGIN)
                                               ; SOURCE LINE # 1
                                               ; SOURCE LINE # 2
                                               ; SOURCE LINE # 5
    ;---- Variable 'loop' assigned to Register 'R7' ----
    0000 E4                CLR     A
    0001 FF                MOV     R7,A
    0002         ?C0001:
                                               ; SOURCE LINE # 6
                                               ; SOURCE LINE # 7
    0002 0F                INC     R7
    0003 BF80FC            CJNE    R7,#080H,?C0001
    0006         ?C0004:
                                               ; SOURCE LINE # 8
    0006 80FE              SJMP    ?C0004
                 ; FUNCTION main (END)
    

    And another one:


    line level source 1 int main(void) 2 { 3 1 unsigned char loop; 4 1 5 1 for(loop = 128; loop-- != 0; ) 6 1 { 7 2 } 8 1 while(1); 9 1 return(0); 10 1 }
    C51 COMPILER V8.02 MAIN 08/15/2007 13:03:32 PAGE 2 ASSEMBLY LISTING OF GENERATED OBJECT CODE ; FUNCTION main (BEGIN) ; SOURCE LINE # 1 ; SOURCE LINE # 2 ; SOURCE LINE # 5
    ;---- Variable 'loop' assigned to Register 'R7' ----
    0000 7F80 MOV R7,#080H
    0002 ?C0001:
    0002 AE07 MOV R6,AR7
    0004 1F DEC R7
    0005 EE MOV A,R6
    0006 70FA JNZ ?C0001 ; SOURCE LINE # 6 ; SOURCE LINE # 7
    0008 ?C0003: ; SOURCE LINE # 8
    0008 80FE SJMP ?C0003 ; FUNCTION main (END)

    If you know the compiler and the right syntax, it is possible to get a djnz when using a for loop. There is no guarantee.

  • "The authoritative masquerade very clearly exposed!"

    Not really.

    All it has shown is that, in one particular case, the for loop just happened to turn out as a simple DJNZ loop.

    In general, you can't assume that.

    eg, in the example shown, the oprimiser has happened to assign the loop counter to R7 - unrelated changes in the source code could change that, which may or may not affect the loop timing!

    One more time: There is absolutely no guarantee whatsoever etc, etc,...

  • The authoritative masquerade very clearly exposed!

    Does "Jack" now need an audience to give some applause whenever he (doesn't) find an error in Erik's arguments ?

    int main(void)
    {
        unsigned char loop;
    
        for(loop = 128; loop != 0; loop--)
        {   }
        while(1);
        return(0);
    }
    

    Here's an easy question:

    Assume nothing about the compiler, except that it is actually working correctly. The for loop above will result in (more than one answer may be correct):

    a) a DJNZ loop
    b) another type of loop
    c) no loop at all