spll_ptracker.c 1.88 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/*
 * This work is part of the White Rabbit project
 *
 * Copyright (C) 2010 - 2013 CERN (www.cern.ch)
 * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
 *
 * Released according to the GNU GPL, version 2 or any later version.
 */

/* spll_ptracker.c - implementation of phase trackers. */

12
#include "softpll_ng.h"
13

14
static int tag_ref = -1;
15

16 17 18
void ptracker_init(struct spll_ptracker_state *s, int id, int num_avgs)
{
	s->id = id;
19 20 21 22
	s->ready = 0;
	s->n_avg = num_avgs;
	s->acc = 0;
	s->avg_count = 0;
23 24
	s->enabled = 0;

25 26 27 28
}

void ptracker_start(struct spll_ptracker_state *s)
{
29 30
	s->preserve_sign = 0;
	s->enabled = 1;
31 32 33 34
	s->ready = 0;
	s->acc = 0;
	s->avg_count = 0;

35 36
	spll_enable_tagger(s->id, 1);
	spll_enable_tagger(spll_n_chan_ref, 1);
37 38
}

39
int ptrackers_update(struct spll_ptracker_state *ptrackers, int tag,
40 41
			   int source)
{
42 43 44 45 46 47 48 49 50 51 52
	const int adj_tab[16] = { /* psign */ 
														/* 0   - 1/4   */  0, 0, 0, -(1<<HPLL_N),
														/* 1/4 - 1/2  */   0, 0, 0, 0,
														/* 1/2 - 3/4  */   0, 0, 0, 0,
														/* 3/4 - 1   */    (1<<HPLL_N), 0, 0, 0};
												
	if(source == spll_n_chan_ref)
	{
		tag_ref = tag;
		return 0;
	}
53 54


55
	register struct spll_ptracker_state *s = ptrackers + source;
56

57 58
	if(!s->enabled)
		return 0;
59

60
	register int delta = (tag - tag_ref) & ((1 << HPLL_N) - 1);
61
	register int index = delta >> (HPLL_N - 2);
62 63


64 65 66 67 68 69 70
	if (s->avg_count == 0) {
		/* hack: two since PTRACK_WRAP_LO/HI are in 1/4 and 3/4 of the scale,
		   we can use the two MSBs of delta and a trivial LUT instead, removing 2 branches */
		s->preserve_sign = index << 2;
		s->acc = delta;
		s->avg_count ++;
	} else {
71

72 73 74
		/* same hack again, using another lookup table to adjust for wraparound */
		s->acc += delta + adj_tab[ index + s->preserve_sign ];
		s->avg_count ++;
75

76 77 78 79 80
		if (s->avg_count == s->n_avg) {
			s->phase_val = s->acc / s->n_avg;
			s->ready = 1;
			s->acc = 0;
			s->avg_count = 0;
81 82 83
		}
	}

84
	return 0;
85
}