Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,11 @@ final_fold2_test
final_fold_constants
final_fold_test
slice_by_8_bench
vec_barrett_reduction_test
vec_final_fold_test
vec_final_fold2_test
vec_crc32_test
vec_crc32_bench
crc32_ethernet_constants.h
crc32k_constants.h
crc32_two_implementations
87 changes: 78 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
CFLAGS=-m64 -g -O2 -Wall
ORIG_CFLAGS:= $(CFLAGS)

CFLAGS+=-m64 -g -O2 -mcpu=power8 -mpower8-vector -Wall
ASFLAGS=-m64 -g
LDFLAGS=-m64 -g -static

SHELL=/bin/bash

# Ethernet CRC
#CRC=0x04C11DB7
#OPTIONS=

# CRC32C
# CRC32
CRC=0x11EDC6F41
OPTIONS=-r -x

Expand All @@ -31,10 +34,18 @@ PROGS=barrett_reduction_constants \


PROGS_ALTIVEC=barrett_reduction_test \
final_fold_test \
final_fold_test \
final_fold2_test \
crc32_test crc32_bench crc32_stress
crc32_test \
crc32_bench \
crc32_stress \
vec_barrett_reduction_test \
vec_final_fold_test \
vec_final_fold2_test \
vec_crc32_bench \
crc32_two_implementations

CRC32_CONSTANTS_OBJS=crc32_constants.o poly_arithmetic.o crcmodel.o
ifeq ($(call cc-option-yn,-maltivec),y)
CFLAGS += -maltivec
ASFLAGS += -maltivec
Expand All @@ -47,21 +58,79 @@ all: $(PROGS)
barrett_reduction_constants: barrett_reduction_constants.o poly_arithmetic.o
final_fold_constants: final_fold_constants.o poly_arithmetic.o
final_fold2_constants: final_fold2_constants.o poly_arithmetic.o
crc32_constants: crc32_constants.o poly_arithmetic.o crcmodel.o
crc32_constants: $(CRC32_CONSTANTS_OBJS)

barrett_reduction_test: barrett_reduction_test.o crcmodel.o barrett_reduction.o
final_fold_test: final_fold_test.o crcmodel.o final_fold.o
final_fold2_test: final_fold2_test.o crcmodel.o final_fold2.o

vec_barrett_reduction_test: vec_barrett_reduction_test.o crcmodel.o \
vec_barrett_reduction.o
vec_final_fold_test: vec_final_fold_test.o crcmodel.o vec_final_fold.o
vec_final_fold2_test: vec_final_fold2_test.o crcmodel.o vec_final_fold2.o


$(CRC32_CONSTANTS_OBJS) : %.o : %.c Makefile
$(CC) -c $(ORIG_CFLAGS) $< -o $@

crc32_constants.h: crc32_constants
$(EMULATOR) ./crc32_constants $(OPTIONS) $(CRC) > crc32_constants.h

vec_crc32_c.o: vec_crc32.c crc32_constants.h
$(CC) -c $(CFLAGS) \
-D CRC32_FUNCTION=crc32_vpmsum_c \
vec_crc32.c -o $@
crc32.o: crc32.S crc32_constants.h
crc32_stress.o: crc32_stress.c crc32_constants.h
crc32_test.o: crc32_test.c crc32_constants.h
crc32_wrapper.o: crc32_wrapper.c crc32_constants.h
crc32_test: crc32_test.o crcmodel.o crc32.o crc32_wrapper.o
crc32_bench: crc32_bench.o crcmodel.o crc32.o crc32_wrapper.o

slice_by_8_bench: crc32_bench.o

crc32_test: crc32_test.o crcmodel.o crc32.o crc32_wrapper.o vec_crc32_c.o
crc32_bench: crc32_bench.o crc32.o crc32_wrapper.o
crc32_stress: crc32_stress.o crcmodel.o crc32.o crc32_wrapper.o

vec_crc32.o: vec_crc32.c crc32_constants.h
vec_crc32_bench: crc32_bench.o vec_crc32.o

vec_crc32_bench:
$(CC) $(LDFLAGS) $^ -o $@

# This is an example of multiple crc32 polynomials being used
# in a single linked file.
crc32_ethernet_constants.h: crc32_constants
$(EMULATOR) ./crc32_constants -c -r -x 0x4c11db7 > $@

vec_crc32_ethernet.o: vec_crc32.c crc32_ethernet_constants.h
$(CC) -c $(CFLAGS) \
-D CRC32_FUNCTION=crc32ethernet \
-D CRC32_CONSTANTS_HEADER=\"crc32_ethernet_constants.h\" \
vec_crc32.c -o $@

crc32k_constants.h: crc32_constants
$(EMULATOR) ./crc32_constants -a -r -x 0x741B8CD7 > $@

crc32k_wrapper.o: crc32_wrapper.c crc32k_constants.h
crc32k.o: crc32.S crc32k_constants.h

crc32k_wrapper.o crc32k.o:
$(CC) -c $(CFLAGS) \
-D CRC32_FUNCTION=crc32k \
-D CRC32_FUNCTION_ASM=crc32k_asm \
-D CRC32_CONSTANTS_HEADER=\"crc32k_constants.h\" \
$< -o $@

crc32_two_implementations: crc32k_wrapper.o crc32k.o vec_crc32_ethernet.o

# implementation has boundaries on datasizes 16 and 256, 32768 so ensure coverage and correctness
test: crc32_test
set -e ; \
for len in `seq 0 257` 32767 32768 32769 65535 65536 65537 ; do \
./crc32_test $${RANDOM} $$len $${RANDOM} ; \
done ; \

clean:
rm -f crc32_constants.h *.o $(PROGS) $(PROGS_ALTIVEC)
rm -f crc32_constants.h crc32k_constants.h crc32_ethernet_constants.h *.o $(PROGS) $(PROGS_ALTIVEC)

.PHONY: clean test all
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,53 @@ to mitigate any I/O induced variability.
Quick start
-----------

There's two different versions of crc32. They are, basically, the same
algorithm. The only difference is that one is implemented in pure assembly
(crc32.S) and the other in C using gcc (power8) vector intrinsics and
builtins (vec_crc32.c) to make the compiler generate the asm instructions
instead.

- Modify CRC and OPTIONS in the Makefile. There are examples for the two most
common crc32s.

- Type make to create the constants (crc32_constants.h)

**If you will use the pure asm version**

- Import the code into your application (crc32.S crc32_wrapper.c
crc32_constants.h ppc-opcode.h) and call the CRC:
crc32_constants.h ppc-opcode.h)

**If you will use the C version**

- Import the code into your application (vec_crc32.c crc32_constants.h)

- Call the CRC:


```
unsigned int crc32_vpmsum(unsigned int crc, unsigned char *p, unsigned long len);
```

Advanced Usage
--------------

Occasionally you may have a number of CRC32 polynomial implementations.

To do this you'll need to compile the C or assembler implementation with a
different constants header file and change the function names to avoid linker
conflicts.

To facilitate this optional defines can be introduced:

- CRC32_CONSTANTS_HEADER to be set to the *quoted* header filename.

- CRC32_FUNCTION to be set to the crc32 function name (instead of crc32_vpmsum)

- CRC32_FUNCTION_ASM (asm version only) to be set to the assember function name used
by crc32_wrapper.c (defaults to __crc32_vpmsum).

An example of this is with crc32_two_implementations as found in the Makefile.

CRC background
--------------

Expand Down Expand Up @@ -233,3 +268,7 @@ Acknowledgements

Thanks to Michael Gschwind, Jeff Derby, Lorena Pesantez and Stewart Smith
for their ideas and assistance.

Thanks Rogerio Alves for writing the C implementation.

Thanks Daniel Black for cleanup and testing.
13 changes: 10 additions & 3 deletions crc32.S
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@
/* byte reverse permute constant */
.octa 0x0F0E0D0C0B0A09080706050403020100

#define __ASSEMBLY__
#ifdef CRC32_CONSTANTS_HEADER
#include CRC32_CONSTANTS_HEADER
#else
#include "crc32_constants.h"
#endif

.text

Expand Down Expand Up @@ -81,8 +84,12 @@
#define VPERM(A, B, C, D)
#endif

#ifndef CRC32_FUNCTION_ASM
#define CRC32_FUNCTION_ASM __crc32_vpmsum
#endif

/* unsigned int __crc32_vpmsum(unsigned int crc, void *p, unsigned long len) */
FUNC_START(__crc32_vpmsum)
FUNC_START(CRC32_FUNCTION_ASM)
std r31,-8(r1)
std r30,-16(r1)
std r29,-24(r1)
Expand Down Expand Up @@ -769,4 +776,4 @@ FUNC_START(__crc32_vpmsum)
mr r3,r10
b .Lout

FUNC_END(__crc32_vpmsum)
FUNC_END(CRC32_FUNCTION_ASM)
4 changes: 3 additions & 1 deletion crc32_bench.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <malloc.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

unsigned int crc32_vpmsum(unsigned int crc, unsigned char *p, unsigned long len);

Expand All @@ -12,7 +13,8 @@ int main(int argc, char *argv[])
unsigned int crc = 0;

if (argc != 3) {
fprintf(stderr, "Usage: crc32_bench length iterations\n");
fprintf(stderr, "Usage: %s length iterations\n", argv[0]);
fprintf(stderr, "Performs crc32 checksum an [iterations] number of times on a buffer filled with junk data of [length] bytes\n");
exit(1);
}

Expand Down
Loading