/* Optimised simple memory checksum * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public Licence * as published by the Free Software Foundation; either version * 2 of the Licence, or (at your option) any later version. */ #include <asm/cache.h> .section .text .balign L1_CACHE_BYTES ############################################################################### # # unsigned int do_csum(const unsigned char *buff, int len) # ############################################################################### .globl do_csum .type do_csum,@function do_csum: movm [d2,d3],(sp) mov d1,d2 # count mov d0,a0 # buff mov a0,a1 clr d1 # accumulator cmp +0,d2 ble do_csum_done # check for zero length or negative # 4-byte align the buffer pointer btst +3,a0 beq do_csum_now_4b_aligned btst +1,a0 beq do_csum_addr_not_odd movbu (a0),d0 inc a0 asl +8,d0 add d0,d1 add -1,d2 do_csum_addr_not_odd: cmp +2,d2 bcs do_csum_fewer_than_4 btst +2,a0 beq do_csum_now_4b_aligned movhu (a0+),d0 add d0,d1 add -2,d2 cmp +4,d2 bcs do_csum_fewer_than_4 do_csum_now_4b_aligned: # we want to checksum as much as we can in chunks of 32 bytes cmp +31,d2 bls do_csum_remainder # 4-byte aligned remainder add -32,d2 mov +32,d3 do_csum_loop: mov (a0+),d0 mov (a0+),e0 mov (a0+),e1 mov (a0+),e3 add d0,d1 addc e0,d1 addc e1,d1 addc e3,d1 mov (a0+),d0 mov (a0+),e0 mov (a0+),e1 mov (a0+),e3 addc d0,d1 addc e0,d1 addc e1,d1 addc e3,d1 addc +0,d1 sub d3,d2 bcc do_csum_loop add d3,d2 beq do_csum_done do_csum_remainder: # cut 16-31 bytes down to 0-15 cmp +16,d2 bcs do_csum_fewer_than_16 mov (a0+),d0 mov (a0+),e0 mov (a0+),e1 mov (a0+),e3 add d0,d1 addc e0,d1 addc e1,d1 addc e3,d1 addc +0,d1 add -16,d2 beq do_csum_done do_csum_fewer_than_16: # copy the remaining whole words cmp +4,d2 bcs do_csum_fewer_than_4 cmp +8,d2 bcs do_csum_one_word cmp +12,d2 bcs do_csum_two_words mov (a0+),d0 add d0,d1 addc +0,d1 do_csum_two_words: mov (a0+),d0 add d0,d1 addc +0,d1 do_csum_one_word: mov (a0+),d0 add d0,d1 addc +0,d1 do_csum_fewer_than_4: and +3,d2 beq do_csum_done xor_cmp d0,d0,+2,d2 bcs do_csum_fewer_than_2 movhu (a0+),d0 and +1,d2 beq do_csum_add_last_bit do_csum_fewer_than_2: movbu (a0),d3 add d3,d0 do_csum_add_last_bit: add d0,d1 addc +0,d1 do_csum_done: # compress the checksum down to 16 bits mov +0xffff0000,d0 and d1,d0 asl +16,d1 add d1,d0 addc +0xffff,d0 lsr +16,d0 # flip the halves of the word result if the buffer was oddly aligned and +1,a1 beq do_csum_not_oddly_aligned swaph d0,d0 # exchange bits 15:8 with 7:0 do_csum_not_oddly_aligned: ret [d2,d3],8 .size do_csum, .-do_csum