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

Using C and reading CPU Register (Carry-Flag) via assembler

Hi smart guys out there,

I am using µVision with TIs eval-kit LM3S9B92. I use µVisions C-Compiler.

I learned that it is not possible to read the CPU-Registers with C and I have to use asembler for that.

I have no idea of asembler and actually I don't work with it in future and I hope I never have to again :-) ...but right now I need to know the status of the carrybit.

So all I am asking is for a piece of code that gets me the status of bit 29 in the register 17 :) and how to implement that in my project.

I hope this doesn't sound sassy ;-) - at least it isn't meant that way.

Thank you so much.

  • A little clue:

    int32u __asm processor_in_user_mode(void)
    {
            STMDB   R13!, {R1}
    
            MRS     R0, CPSR
            AND     R0, R0, #0x1F   // the lowest 5 bits of CPSR respresent the processor mode
            MOV             R1, #0x10               // user mode = 0x10
            CMP             R0, R1
            BEQ             not_interrupt_context
    
            LDMIA   R13!, {R1} // restore the file name and the line number.
    
            MOV             R0,     #0x0 // indicate called while not in user mode
    
            BX              LR
    
    not_interrupt_context
    
            // restore original values of R1
            LDMIA   R13!, {R1}
    
            MOV             R0,     #0x1 // indicate called while in user mode
    
            BX              LR
    }
    

    Assuming you are working with an ARM7 core, you are interested in CRSR. What is that according to the user manual...?

  • For the sake of completeness -

    STMDB   R13!, {R1}
    


    and

    LDMDB   R13!, {R1}
    

    above can be discarded.

  • you are interested in CRSR -> you are interested in CPSR

  • Hey Tamir,
    thanks for your fast reply.

    I am working on an ARM Cortex-M3. CPSR was unknown to the compiler, but APSR wasn't :)
    Anyways, I placed your code (with CPSR changed to APSR) in a new .c file and it compiled without grumping :]

    For evaluation I tried that:

    int
    main(void)
    {
            unsigned long dummy;
            unsigned long a=1000;
            unsigned long b=10000;
    
            dummy = a - b;  //Carry-bit should be set
            UARTprintf("\n: %d \n", processor_in_user_mode);
            dummy = b - a;//Carry-bit shouldn't be set
            UARTprintf("\n: %d \n", processor_in_user_mode);
    

    but both times it prints out '489' which is:

    111101001

    so nothing changed. But register 17 bit 31 is according to the datasheet the carry bit, which should have changed here...
    I also tried PSR instead of APSR: no change

    By the way: CPSR is printed bold in code, PSR or APSR isn't.

  • Hi Susan

    Couple of options:

    Use this standardized CMSIS function portable between popular toolchains

    __get_APSR(void)
    

    Or use MDK/RVCT specific named register variables

    uint32_t apsr __asm("APSR");
    
    if (apsr & APSR_C)
       // do this
    else
       // do that
    

    Hope this helps
    Marcus

  • Note that you can manage quite well without ever knowing the content of the carry bit.

    if (b >= a) {
        b -= a;
        // no borrow
    } else {
        b -= a;
        // handle borrow
    }
    
    unsigned a,b,c;
    c = a+b;
    if (c < a || c < b) {
        // addition overflow
    }
    

  • ...but right now I need to know the status of the carrybit.

    That's most probably an incorrect belief.

    Note that even if you find a method for reading the carry flag, there's absolutely no guarantee that by the time that method actually accesses it the carry still contains the same state you were looking for. Compiled C code owns that flag --- it'll do with it whatever it wants, up to and including using it for some other purpose in the meantime.

    In a nutshell, when you think you need the carry flag (or the content of any general-purpose register) from inside a C program, you're still thinking in assembler. And that will not work.


  • That is very probably an incorrect belief.

    So, instead, why don't you tell us what you're actually trying to achieve here?

    www.catb.org/.../smart-questions.html

  • Point taken - didn't know that C works that way (owning the carry bit).
    Would it work, if the prior calculation was in assembler, too? 'Cause I thought that the codepart written in assembler will be transcoded to machinecode in a coherent way...won't it?

    I wanted to avoid the method Per suggested, because I was just curious if it is possible to avoid it. That was my single goal: Curiosity :-) . Stupid, I guess.

    Now I will just do it the standard way without using assembler.

    Thanks a lot for your help!

  • Marcus, I tried yours, too.

    __get_APSR(void)

    Do I need a special header or include file for this?
    Cause µVision tells me:

    undefined symbol __get_APSR();

    identifier "APSR_C" is undefined, respectively (when trying the other one)

  • __get_APSR() is defined in CMSIS, so yes, you do need to include a header file, namely core_cmFunc.h.

    The identifier APSR_C was just a made up example, perhaps defined as macro, to demonstrate that you need to compare with a numeric value. BTW, CMSIS also defines a structure APSR_Type so that you could perhaps write something like:

    if ((APSR_Type)apsr.b.C)
      // do this
    else
      // do that
    


    But as others have said already: For your purposes, this is completely unnecessary.

    Best regards
    Marcus

  • The ARM compiler is "smart" enough that it merges the assembler instructions with the instructions generated from the C code. Then it performs a number of optimization steps.

    So inlined assembler need not survive unmodified to the finaly binary.

    If you want to implement a large-number library while using the carry flag, then you should implement the evaluations fully in assembler.

    Note that a comparison "if (a >= b)" is very fast on the ARM processor, and the optimizer will recognize that it's the same variables in the comparison as in the actual subtraction. So no extra memory accesses. Just a comparison. And the optimizer might even note that the comparison and the subtraction are basically the same thing, and the code is still interested in a subtraction.

    When programming in C - do stay with C. Do not try to fool the optimizer by taking short cuts. When you are not happy with C, because of special needs: write full functions in assembler.

  • That's the whole point of any high-level language (HLL) - you delegate responsibility for the low-level detail to the compiler.

  • Thanks a lot guys,
    I will stay with C :-]