1 /* K=15 r=1/6 Viterbi decoder in portable C 2 * Copyright Mar 2004, Phil Karn, KA9Q 3 * May be used under the terms of the GNU Lesser General Public License (LGPL) 4 */ 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <memory.h> 8 #include <limits.h> 9 #include "fec.h" 10 11 typedef union { unsigned long w[512]; unsigned char c[2048];} decision_t; 12 typedef union { unsigned long w[16384]; } metric_t; 13 14 static union branchtab615 { unsigned long w[8192]; } Branchtab615[6] __attribute__ ((aligned(16))); 15 static int Init = 0; 16 17 /* State info for instance of Viterbi decoder */ 18 struct v615 { 19 metric_t metrics1; /* path metric buffer 1 */ 20 metric_t metrics2; /* path metric buffer 2 */ 21 decision_t *dp; /* Pointer to current decision */ 22 metric_t *old_metrics,*new_metrics; /* Pointers to path metrics, swapped on every bit */ 23 decision_t *decisions; /* Beginning of decisions for block */ 24 }; 25 26 /* Create a new instance of a Viterbi decoder */ 27 void *create_viterbi615_port(int len){ 28 struct v615 *vp; 29 30 if(!Init){ 31 int polys[6] = { V615POLYA,V615POLYB,V615POLYC,V615POLYD,V615POLYE,V615POLYF }; 32 set_viterbi615_polynomial_port(polys); 33 } 34 if((vp = (struct v615 *)malloc(sizeof(struct v615))) == NULL) 35 return NULL; 36 if((vp->decisions = malloc((len+14)*sizeof(decision_t))) == NULL){ 37 free(vp); 38 return NULL; 39 } 40 init_viterbi615(vp,0); 41 return vp; 42 } 43 44 void set_viterbi615_polynomial_port(int polys[6]){ 45 int state; 46 int i; 47 48 for(state=0;state < 8192;state++){ 49 for(i=0;i<6;i++) 50 Branchtab615[i].w[state] = (polys[i] < 0) ^ parity((2*state) & abs(polys[i])) ? 255 : 0; 51 } 52 Init++; 53 } 54 55 /* Initialize Viterbi decoder for start of new frame */ 56 int init_viterbi615_port(void *p,int starting_state){ 57 struct v615 *vp = p; 58 int i; 59 60 if(p == NULL) 61 return -1; 62 for(i=0;i<16384;i++) 63 vp->metrics1.w[i] = 1000; 64 65 vp->old_metrics = &vp->metrics1; 66 vp->new_metrics = &vp->metrics2; 67 vp->dp = vp->decisions; 68 vp->old_metrics->w[starting_state & 16383] = 0; /* Bias known start state */ 69 return 0; 70 } 71 72 /* Viterbi chainback */ 73 int chainback_viterbi615_port( 74 void *p, 75 unsigned char *data, /* Decoded output data */ 76 unsigned int nbits, /* Number of data bits */ 77 unsigned int endstate){ /* Terminal encoder state */ 78 struct v615 *vp = p; 79 decision_t *d; 80 81 if(p == NULL) 82 return -1; 83 d = (decision_t *)vp->decisions; 84 endstate %= 16384; 85 86 /* The store into data[] only needs to be done every 8 bits. 87 * But this avoids a conditional branch, and the writes will 88 * combine in the cache anyway 89 */ 90 d += 14; /* Look past tail */ 91 while(nbits-- != 0){ 92 int k; 93 94 k = (d[nbits].c[endstate/8] >> (endstate%8)) & 1; 95 endstate = (k << 13) | (endstate >> 1); 96 data[nbits>>3] = endstate >> 6; 97 } 98 return 0; 99 } 100 101 /* Delete instance of a Viterbi decoder */ 102 void delete_viterbi615_port(void *p){ 103 struct v615 *vp = p; 104 105 if(vp != NULL){ 106 free(vp->decisions); 107 free(vp); 108 } 109 } 110 111 /* C-language butterfly */ 112 #define BFLY(i) {\ 113 unsigned long metric,m0,m1,m2,m3,decision0,decision1;\ 114 metric = ((Branchtab615[0].w[i] ^ syms[0]) + (Branchtab615[1].w[i] ^ syms[1])\ 115 +(Branchtab615[2].w[i] ^ syms[2]) + (Branchtab615[3].w[i] ^ syms[3])\ 116 +(Branchtab615[4].w[i] ^ syms[4]) + (Branchtab615[5].w[i] ^ syms[5]));\ 117 m0 = vp->old_metrics->w[i] + metric;\ 118 m1 = vp->old_metrics->w[i+8192] + (1530 - metric);\ 119 m2 = vp->old_metrics->w[i] + (1530-metric);\ 120 m3 = vp->old_metrics->w[i+8192] + metric;\ 121 decision0 = (signed long)(m0-m1) >= 0;\ 122 decision1 = (signed long)(m2-m3) >= 0;\ 123 vp->new_metrics->w[2*i] = decision0 ? m1 : m0;\ 124 vp->new_metrics->w[2*i+1] = decision1 ? m3 : m2;\ 125 d->c[i/4] |= ((decision0|(decision1<<1)) << ((2*i)&7));\ 126 } 127 /* Update decoder with a block of demodulated symbols 128 * Note that nbits is the number of decoded data bits, not the number 129 * of symbols! 130 */ 131 132 int update_viterbi615_blk_port(void *p,unsigned char *syms,int nbits){ 133 struct v615 *vp = p; 134 void *tmp; 135 decision_t *d; 136 int i; 137 138 if(p == NULL) 139 return -1; 140 d = (decision_t *)vp->dp; 141 while(nbits--){ 142 memset(d,0,sizeof(decision_t)); 143 for(i=0;i<8192;i++) 144 BFLY(i); 145 146 syms += 6; 147 d++; 148 /* Swap pointers to old and new metrics */ 149 tmp = vp->old_metrics; 150 vp->old_metrics = vp->new_metrics; 151 vp->new_metrics = tmp; 152 } 153 vp->dp = d; 154 return 0; 155 } 156 157