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

How to perform 6 byte addition with efficiency using C code

unsigned long ul1=XX, ul2=YY, ul;
unsigned int ui1=AA, ui2=BB, ui;

ui=ui1+ui2;
ul=ul1+(ul2+(unsigned long)CY);

very inefficient code is generated by C51.
but this can be done using ADC (add with carry) if assembly is used.

Is there any way in C itself, to perform 6 byte addition?

Parents

  • True; the only reason that the variable "c" exists is to try to snag the carry flag before later ADDs in the loop control code change it. And the success of that scheme, of course, is highly dependent on your code generator. You'll be looking at the assembly output anyway; might as well just write the routine in assembler to start with.

    Another way to tackle the problem is to do the U8 addition in a U16, so you wind up with the carry bit in an actual C variable, instead of relying on quirks of the compiler and architecture:

    void U48AddEq (U8 data* dst, U8 data* src, U8 len)
        {
        U16 temp = 0;
    
        while (len--)
            {
            temp += dst[len] + src[len];
    	dst[len] = (U8)temp;
            temp >>= 8;
            }
        }
    
    

    The Keil compiler isn't always good at recognizing opportunities to do strength reduction on shifts by multiples of 8, though. Might have to descend to some hackery to get the high half of temp into the low half with one MOV. Of course, the pointer dereferencing and loop overhead are going to swamp the cost of the actual addition here in any case. Ultimately, you've got the problem that two 6-byte integers don't fit in 8 bytes of register.

    (I'm curious; why 6 bytes, and not 8? Ethernet MAC addresses? Not that you need to add those a lot.)

Reply

  • True; the only reason that the variable "c" exists is to try to snag the carry flag before later ADDs in the loop control code change it. And the success of that scheme, of course, is highly dependent on your code generator. You'll be looking at the assembly output anyway; might as well just write the routine in assembler to start with.

    Another way to tackle the problem is to do the U8 addition in a U16, so you wind up with the carry bit in an actual C variable, instead of relying on quirks of the compiler and architecture:

    void U48AddEq (U8 data* dst, U8 data* src, U8 len)
        {
        U16 temp = 0;
    
        while (len--)
            {
            temp += dst[len] + src[len];
    	dst[len] = (U8)temp;
            temp >>= 8;
            }
        }
    
    

    The Keil compiler isn't always good at recognizing opportunities to do strength reduction on shifts by multiples of 8, though. Might have to descend to some hackery to get the high half of temp into the low half with one MOV. Of course, the pointer dereferencing and loop overhead are going to swamp the cost of the actual addition here in any case. Ultimately, you've got the problem that two 6-byte integers don't fit in 8 bytes of register.

    (I'm curious; why 6 bytes, and not 8? Ethernet MAC addresses? Not that you need to add those a lot.)

Children
No data