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

Use MACRO C "#define value" in MACRO ASM

I use KeilC uVision4 for 89C51 MCU.
I use "Inline ASM Code", like this :

    void main() {
        #pragma ASM
            MOV R7, #(80000/40000)
        #pragma ENDASM
    }


-> When COMPILE, ASM result file give a wrong value to R7

        MOV R7, #0x00


But when i change like this :

    void main() {
        #pragma ASM
            MOV R7, #(60000/30000)
        #pragma ENDASM
    }


-> The COMPILER give correct value to R7

        MOV R7, #0x02


=> Seem, there must be a restriction when the ASM Compiler calculate (80000/40000) ?
=> And is there any way to pass this restriction. Please help me !
Regards !

  • Well, maybe AX51 compiler can pass this restriction.

    When i first create my project, I choose "LX51 & AX51 instead of old BL51 & A51", then everything works fine. Thanks !

  • I don't know your chip at all, but it is striking that 60000 is just under an unsigned 16 bit integer value limit (2^16 - 1), 80000 slightly above...

  • Well, I intend to write an Accurate "ASM Delay Routine" by "Inline ASM".

    Let take the simplest delay code:

        #pragma ASM
        MOV R1, #vR1
        // Calculate Time spent From Here
        DJNZ R1, $ //2 Machine cycle (MCs)
        #pragma ENDASM
    


    With 8051MCU, it spent : t1 = vR1 x 2 machine cycles (MCs)

    Now, with 2 registers used:

        #pragma ASM
        MOV R1, #vR1
        MOV R2, #vR2
        // Calculate Time spent From Here
        DJNZ R1, $
        DJNZ R2, $-2
        #pragma ENDASM
    


    time spent : t2 = (t1 + 257vR2 - 256) x 2 MCs

    Finally, with 3 registers used:

        #pragma ASM
        MOV R1, #vR1
        MOV R2, #vR2
        MOV R3, #vR3
        DJNZ R1, $
        DJNZ R2, $-2
        DJNZ R3, $-4
        #pragma ENDASM
    


    time spent : t3 = (t2 + 65793vR3 - 65792) x 2 MCs

    Generraly, with n Register used, we can delay :

    tn = (tn-1 + (Cn-1 + 1)vRn - Cn-1) x 2 MCs
    where :

    Cn = 256^n + 256^(n-1) + ... + 256 + 0

    Now i write a delay 3000MCs routine :

    //8051 MCU
    #define Interval 3000 // Change here to change delay in MCs)
    
    #define C0 0                 // Constant in formula above
    #define C1 256               // Constant
    #define C2 65792             // Constant
    
    #define t3 Interval/2        // DJNZ take 2 MCs, so divide by 2 for easier calculation
    #define vR3 ((t3+C2-2)/(C2+1))   // Calculate R3 value
    
    #define t2  (t3+C2-(C2+1)*vR3)
    #define vR2 ((t2+C1-1)/(C1+1))   // Calculate R2 value
    
    #define t1  (t2+C1-(C2+1)*vR2)
    #define vR1 ((t1+C0-0)/(C0+1))   // Calculate R1 value
    
    void Delay() {
        #pragma ASM
        MOV R1, #vR1
        MOV R2, #vR2
        MOV R3, #vR3
        DJNZ R1, $
        DJNZ R2, $-2
        DJNZ R3, $-4
        #pragma ENDASM
    }
    


    Use in main routine :

    void main() {
        Delay(); // Delay 3000 Machine Cycles
    }
    

    => For easier use, i should write a DelayMCs() Macro, eg :

        #define DelayMCs(Interval) //Code Here???
    


    Then, use this Macro like this :

    void main() {
        DelayMCs(7000);
    }
    


    => That's my idea. But i don't know how to write this Macro. Can anyone help me build "Code Here" above. Thanks !

  • In my opinion, this would be a perfect place to use a little assembly module.

  • "A little ASM Module", did you mean : write that Delay routines in a seperate ASM file ??? I think we have to use MACRO here ???

  • Yes, in an asm file.

    Macros, as always, are optional.

  • But i don't want to use MCU to calculate vR3, vR2, vR1, let the Compiler do that, then just add the result of vR3, vR2, vR1 to the Delay() Routines.

    void Delay() {
        #pragma ASM
        MOV R1, #vR1 // vR1 calculate from Compiler
        MOV R2, #vR2 // vR2 calculate from Compiler
        MOV R3, #vR3 // vR3 calculate from Compiler
        DJNZ R1, $
        DJNZ R2, $-2
        DJNZ R3, $-4
        #pragma ENDASM
    }
    

    I mean that, in the main routine, i call Delay MACRO :

    void main() {
       DelayMCs(3000); // 3000 are numeric const, not variable
    }
    


    then the compiler scan and compile this MACRO to something like :

    #define Interval 3000
    #define t3 Interval/2
    #define vR3 ((t3+C2-2)/(C2+1))
    #define t2 (t3+C2-(C2+1)*vR3)
    #define vR2 ((t2+C1-1)/(C1+1))
    #define t1  (t2+C1-(C2+1)*vR2)
    #define vR1 ((t1+C0-0)/(C0+1))
    Delay();
    


    So vR1, vR2, vR3 is calculated from Compiler
    Just "Delay();" is compile to code to download to MCU

  • I totally agree!

    That is, a separate Assembly source file; eg, delay.s

    As already noted, manually hacking the registers used internally be 'C' is a Really Bad Idea!

    Instructions on how to do exactly this here: www.8052.com/.../149030

    Simples!

  • You don't have to!

    "let the Compiler do that"

    It will!

    "then just add the result of vR3, vR2, vR1 to the Delay() Routines"

    You don't need to do any of that, either!

    Simply follow the instructions that I just posted...

  • Thanks a lot for your helps. In a couple of days, I found that the Macro should be as following :

    // Delay Routine
    void RoutineDelayMCs(unsigned int interval) {
        #pragma ASM
            DJNZ R7, $
            DJNZ R6, $-2
        #pragma ENDASM
    }
    
    // Delay Macro -> Calculate interval to pass into Delay Routine
    #define MacroDelayMCs(interval) \ 
        ((!(((interval)/2) - 257*((((interval)/2)+256-1)/257))) ? \ 
        RoutineDelayMCs(257*((((interval)/2)+256-1)/257)) : RoutineDelayMCs(((interval)/2)+256-(((interval)/2)+256-1)/257))
    
    // Offset Macro -> Calculate offset MCs of MOV, LCALL, RET ... command -> for better accuracy
    // Accuracy (if interval even, error = 0; if interval odd, error = -1 MCs
    // interval apply Range : 14 -> 131592
    #define DelayMCs(interval) \ 
        MacroDelayMCs(interval-10)
    
    
    void main() {
        DelayMCs(14);     // This call delay 14 Machine Cycles
        DelayMCs(512);    // This call delay 512 MCs
        DelayMCs(131592); // This call delay 131592 MCs
    }
    

    And ... It works fine !
    Of course, manually hacking the registers is really Bad. I will put the RoutineDelayMCs in an ASM Module later.

    Thanks again ... all friends, Regards !