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 12static enum {UNKNOWN=0,MMX,SSE,SSE2,ALTIVEC,PORT} cpu_mode; 13 14static void encode_rs_8_c(data_t *data, data_t *parity,int pad); 15#if __vec__ 16static void encode_rs_8_av(data_t *data, data_t *parity,int pad); 17#endif 18#if __i386__ 19int cpu_features(void); 20#endif 21 22void 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 70static vector unsigned char reverse = (vector unsigned char)(0,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1); 71static 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 */ 77extern static union { vector unsigned char v; unsigned char c[16]; } table[256]; 78 79static 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 */ 105static void encode_rs_8_c(data_t *data, data_t *parity,int pad){ 106 107#include "encode_rs.h" 108 109} 110