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 } 110