lwip operating system abstraction layer implementation based on CMSIS-RTOS

Dependents:   LwIPNetworking NetServicesMin EthernetInterface EthernetInterface_RSF ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers checksum.c Source File

checksum.c

00001 /* Copyright (C) 2013 - Adam Green (https://github.com/adamgreen)
00002 
00003    Licensed under the Apache License, Version 2.0 (the "License");
00004    you may not use this file except in compliance with the License.
00005    You may obtain a copy of the License at
00006 
00007        http://www.apache.org/licenses/LICENSE-2.0
00008 
00009    Unless required by applicable law or agreed to in writing, software
00010    distributed under the License is distributed on an "AS IS" BASIS,
00011    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012    See the License for the specific language governing permissions and
00013    limitations under the License.
00014 */
00015 #if defined(TOOLCHAIN_GCC) && defined(__thumb2__)
00016 
00017 
00018 /* This is a hand written Thumb-2 assembly language version of the
00019    algorithm 3 version of lwip_standard_chksum in lwIP's inet_chksum.c.  It
00020    performs the checksumming 32-bits at a time and even unrolls the loop to
00021    perform two of these 32-bit adds per loop iteration.
00022    
00023    Returns:
00024         16-bit 1's complement summation (not inversed).
00025         
00026    NOTE: This function does return a uint16_t from the assembly language code
00027          but is marked as void so that GCC doesn't issue warning because it
00028          doesn't know about this low level return.
00029 */
00030 __attribute__((naked)) void /*uint16_t*/ thumb2_checksum(const void* pData, int length)
00031 {
00032     __asm (
00033         ".syntax unified\n"
00034         ".thumb\n"
00035 
00036         // Push non-volatile registers we use on stack.  Push link register too to
00037         // keep stack 8-byte aligned and allow single pop to restore and return.
00038         "    push        {r4, lr}\n"
00039         // Initialize sum, r2, to 0.
00040         "    movs    r2, #0\n"
00041         // Remember whether pData was at odd address in r3.  This is used later to
00042         // know if it needs to swap the result since the summation will be done at
00043         // an offset of 1, rather than 0.
00044         "    ands    r3, r0, #1\n"
00045         // Need to 2-byte align?  If not skip ahead.
00046         "    beq     1$\n"
00047         // We can return if there are no bytes to sum.
00048         "    cbz     r1, 9$\n"
00049 
00050         // 2-byte align.
00051         // Place the first data byte in odd summation location since it needs to be
00052         // swapped later.  It's ok to overwrite r2 here as it only had a value of 0
00053         // up until now.  Advance r0 pointer and decrement r1 length as we go.
00054         "    ldrb    r2, [r0], #1\n"
00055         "    lsls    r2, r2, #8\n"
00056         "    subs    r1, r1, #1\n"
00057 
00058         // Need to 4-byte align?  If not skip ahead.
00059         "1$:\n"
00060         "    ands    r4, r0, #3\n"
00061         "    beq     2$\n"
00062         // Have more than 1 byte left to align?  If not skip ahead to take care of
00063         // trailing byte.
00064         "    cmp     r1, #2\n"
00065         "    blt     7$\n"
00066 
00067         // 4-byte align.
00068         "    ldrh    r4, [r0], #2\n"
00069         "    adds    r2, r2, r4\n"
00070         "    subs    r1, r1, #2\n"
00071 
00072         // Main summing loop which sums up data 2 words at a time.
00073         // Make sure that we have more than 7 bytes left to sum.
00074         "2$:\n"
00075         "    cmp     r1, #8\n"
00076         "    blt     3$\n"
00077         // Sum next two words.  Applying previous upper 16-bit carry to
00078         // lower 16-bits.
00079         "    ldr     r4, [r0], #4\n"
00080         "    adds    r2, r4\n"
00081         "    adc     r2, r2, #0\n"
00082         "    ldr     r4, [r0], #4\n"
00083         "    adds    r2, r4\n"
00084         "    adc     r2, r2, #0\n"
00085         "    subs    r1, r1, #8\n"
00086         "    b       2$\n"
00087 
00088         // Sum up any remaining half-words.
00089         "3$:\n"
00090         // Make sure that we have more than 1 byte left to sum.
00091         "    cmp     r1, #2\n"
00092         "    blt     7$\n"
00093         // Sum up next half word, continue to apply carry.
00094         "    ldrh    r4, [r0], #2\n"
00095         "    adds    r2, r4\n"
00096         "    adc     r2, r2, #0\n"
00097         "    subs    r1, r1, #2\n"
00098         "    b       3$\n"
00099 
00100         // Handle trailing byte, if it exists
00101         "7$:\n"
00102         "    cbz     r1, 8$\n"
00103         "    ldrb    r4, [r0]\n"
00104         "    adds    r2, r4\n"
00105         "    adc     r2, r2, #0\n"
00106 
00107         // Fold 32-bit checksum into 16-bit checksum.
00108         "8$:\n"
00109         "    ubfx    r4, r2, #16, #16\n"
00110         "    ubfx    r2, r2, #0, #16\n"
00111         "    adds    r2, r4\n"
00112         "    ubfx    r4, r2, #16, #16\n"
00113         "    ubfx    r2, r2, #0, #16\n"
00114         "    adds    r2, r4\n"
00115 
00116         // Swap bytes if started at odd address
00117         "    cbz     r3, 9$\n"
00118         "    rev16   r2, r2\n"
00119 
00120         // Return final sum.
00121         "9$: mov     r0, r2\n"
00122         "    pop     {r4, pc}\n"
00123     );
00124 }
00125 
00126 #endif