Bill Yi | 4e213d5 | 2015-06-23 13:53:11 -0700 | [diff] [blame] | 1 | /* Reed-Solomon encoder |
| 2 | * Copyright 2004, Phil Karn, KA9Q |
| 3 | * May be used under the terms of the GNU Lesser General Public License (LGPL) |
| 4 | */ |
| 5 | #include <string.h> |
| 6 | #include "fixed.h" |
| 7 | #ifdef __VEC__ |
| 8 | #include <sys/sysctl.h> |
| 9 | #endif |
| 10 | |
| 11 | |
| 12 | static enum {UNKNOWN=0,MMX,SSE,SSE2,ALTIVEC,PORT} cpu_mode; |
| 13 | |
| 14 | static void encode_rs_8_c(data_t *data, data_t *parity,int pad); |
| 15 | #if __vec__ |
| 16 | static void encode_rs_8_av(data_t *data, data_t *parity,int pad); |
| 17 | #endif |
| 18 | #if __i386__ |
| 19 | int cpu_features(void); |
| 20 | #endif |
| 21 | |
| 22 | void encode_rs_8(data_t *data, data_t *parity,int pad){ |
| 23 | if(cpu_mode == UNKNOWN){ |
| 24 | #ifdef __i386__ |
| 25 | int f; |
| 26 | /* Figure out what kind of CPU we have */ |
| 27 | f = cpu_features(); |
| 28 | if(f & (1<<26)){ /* SSE2 is present */ |
| 29 | cpu_mode = SSE2; |
| 30 | } else if(f & (1<<25)){ /* SSE is present */ |
| 31 | cpu_mode = SSE; |
| 32 | } else if(f & (1<<23)){ /* MMX is present */ |
| 33 | cpu_mode = MMX; |
| 34 | } else { /* No SIMD at all */ |
| 35 | cpu_mode = PORT; |
| 36 | } |
| 37 | #elif __VEC__ |
| 38 | /* Ask the OS if we have Altivec support */ |
| 39 | int selectors[2] = { CTL_HW, HW_VECTORUNIT }; |
| 40 | int hasVectorUnit = 0; |
| 41 | size_t length = sizeof(hasVectorUnit); |
| 42 | int error = sysctl(selectors, 2, &hasVectorUnit, &length, NULL, 0); |
| 43 | if(0 == error && hasVectorUnit) |
| 44 | cpu_mode = ALTIVEC; |
| 45 | else |
| 46 | cpu_mode = PORT; |
| 47 | #else |
| 48 | cpu_mode = PORT; |
| 49 | #endif |
| 50 | } |
| 51 | switch(cpu_mode){ |
| 52 | #if __vec__ |
| 53 | case ALTIVEC: |
| 54 | encode_rs_8_av(data,parity,pad); |
| 55 | return; |
| 56 | #endif |
| 57 | #if __i386__ |
| 58 | case MMX: |
| 59 | case SSE: |
| 60 | case SSE2: |
| 61 | #endif |
| 62 | default: |
| 63 | encode_rs_8_c(data,parity,pad); |
| 64 | return; |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | #if __vec__ /* PowerPC G4/G5 Altivec instructions are available */ |
| 69 | |
| 70 | static vector unsigned char reverse = (vector unsigned char)(0,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1); |
| 71 | static vector unsigned char shift_right = (vector unsigned char)(15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30); |
| 72 | |
| 73 | /* Lookup table for feedback multiplications |
| 74 | * These are the low half of the coefficients. Since the generator polynomial is |
| 75 | * palindromic, we form the other half by reversing this one |
| 76 | */ |
| 77 | extern static union { vector unsigned char v; unsigned char c[16]; } table[256]; |
| 78 | |
| 79 | static void encode_rs_8_av(data_t *data, data_t *parity,int pad){ |
| 80 | union { vector unsigned char v[2]; unsigned char c[32]; } shift_register; |
| 81 | int i; |
| 82 | |
| 83 | shift_register.v[0] = (vector unsigned char)(0); |
| 84 | shift_register.v[1] = (vector unsigned char)(0); |
| 85 | |
| 86 | for(i=0;i<NN-NROOTS-pad;i++){ |
| 87 | vector unsigned char feedback0,feedback1; |
| 88 | unsigned char f; |
| 89 | |
| 90 | f = data[i] ^ shift_register.c[31]; |
| 91 | feedback1 = table[f].v; |
| 92 | feedback0 = vec_perm(feedback1,feedback1,reverse); |
| 93 | |
| 94 | /* Shift right one byte */ |
| 95 | shift_register.v[1] = vec_perm(shift_register.v[0],shift_register.v[1],shift_right) ^ feedback1; |
| 96 | shift_register.v[0] = vec_sro(shift_register.v[0],(vector unsigned char)(8)) ^ feedback0; |
| 97 | shift_register.c[0] = f; |
| 98 | } |
| 99 | for(i=0;i<NROOTS;i++) |
| 100 | parity[NROOTS-i-1] = shift_register.c[i]; |
| 101 | } |
| 102 | #endif |
| 103 | |
| 104 | /* Portable C version */ |
| 105 | static void encode_rs_8_c(data_t *data, data_t *parity,int pad){ |
| 106 | |
| 107 | #include "encode_rs.h" |
| 108 | |
| 109 | } |