1139749Simp/*-
2117632Sharti * Copyright (c) 2003
3117632Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4117632Sharti * 	All rights reserved.
5117632Sharti *
6117632Sharti * Redistribution and use in source and binary forms, with or without
7117632Sharti * modification, are permitted provided that the following conditions
8117632Sharti * are met:
9117632Sharti * 1. Redistributions of source code must retain the above copyright
10117632Sharti *    notice, this list of conditions and the following disclaimer.
11117632Sharti * 2. Redistributions in binary form must reproduce the above copyright
12117632Sharti *    notice, this list of conditions and the following disclaimer in the
13117632Sharti *    documentation and/or other materials provided with the distribution.
14117632Sharti *
15117632Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16117632Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17117632Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18117632Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19117632Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20117632Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21117632Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22117632Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23117632Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24117632Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25117632Sharti * SUCH DAMAGE.
26117632Sharti *
27117632Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28117632Sharti *
29117632Sharti * This program is used to generate the different rate tables for the IDT77252
30117632Sharti * driver. The generated tables are slightly different from those in the
31117632Sharti * IDT manual.
32117632Sharti */
33117632Sharti#include <sys/cdefs.h>
34117632Sharti__FBSDID("$FreeBSD$");
35117632Sharti
36117632Sharti#include <sys/types.h>
37117632Sharti#include <stdio.h>
38117632Sharti#include <unistd.h>
39117632Sharti#include <math.h>
40117632Sharti#include <ieeefp.h>
41117632Sharti
42117632Sharti/* verbosity flag */
43117632Shartistatic int verbose;
44117632Sharti
45117632Sharti/* number of table entries */
46117632Shartistatic const u_int tsize = 256;
47117632Sharti
48117632Sharti/* number of rate difference tables to create */
49117632Shartistatic const u_int ndtables = 16;
50117632Sharti
51117632Sharti/* cell rate offset for log 0 */
52117632Shartistatic const double offset = 10.0;
53117632Sharti
54117632Sharti/*
55117632Sharti * Make an internal form of the interval and be sure to round down.
56117632Sharti */
57117632Shartistatic u_int
58117632Shartid2interval(double d)
59117632Sharti{
60117632Sharti	fp_rnd_t r;
61117632Sharti	u_int s, id;
62117632Sharti
63117632Sharti	r = fpsetround(FP_RZ);
64117632Sharti	id = (u_int)rint(32 * d);
65117632Sharti	fpsetround(r);
66117632Sharti
67117632Sharti	s = 0;
68117632Sharti	while (id >= 32 * 32) {
69117632Sharti		s++;
70117632Sharti		id >>= 1;
71117632Sharti	}
72117632Sharti	return ((s << 10) | (id));
73117632Sharti}
74117632Sharti
75117632Sharti/*
76117632Sharti * Convert an internal interval back to a real one.
77117632Sharti */
78117632Shartistatic double
79117632Shartiinterval2d(u_int id)
80117632Sharti{
81117632Sharti	return ((1 << ((id >> 10) & 0xf)) * ((id & 0x3ff) / 32.0));
82117632Sharti}
83117632Sharti
84117632Sharti/*
85117632Sharti * Convert double to ATM-Forum format. Make sure to round up.
86117632Sharti */
87117632Shartistatic u_int
88117632Sharticps2atmf(double cps)
89117632Sharti{
90117632Sharti	fp_rnd_t r;
91117632Sharti	u_int s, id;
92117632Sharti
93117632Sharti	if (cps < 1.0)
94117632Sharti		return (0);
95117632Sharti
96117632Sharti	s = 0;
97117632Sharti	while (cps >= 2.0) {
98117632Sharti		s++;
99117632Sharti		cps /= 2;
100117632Sharti	}
101117632Sharti	r = fpsetround(FP_RP);
102117632Sharti	id = (u_int)rint(512 * cps);
103117632Sharti	fpsetround(r);
104117632Sharti
105117632Sharti	return ((1 << 14) | (s << 9) | (id & 0x1ff));
106117632Sharti}
107117632Sharti
108117632Sharti/*
109117632Sharti * Convert ATM forum format to double
110117632Sharti */
111117632Shartistatic double
112117632Shartiatmf2cps(u_int atmf)
113117632Sharti{
114117632Sharti	return (((atmf >> 14) & 1) * (1 << ((atmf >> 9) & 0x1f)) *
115117632Sharti	    ((512 + (atmf & 0x1ff)) / 512.0));
116117632Sharti}
117117632Sharti
118117632Sharti/*
119117632Sharti * A cell rate to the logarithmic one
120117632Sharti */
121117632Shartistatic double
122117632Sharticps2log(u_int alink, double lg)
123117632Sharti{
124117632Sharti	if (lg <= offset)
125117632Sharti		return (0);
126117632Sharti	if (lg >= alink)
127117632Sharti		return (tsize - 1);
128117632Sharti
129117632Sharti	return ((tsize - 1) * (1 - log(alink / lg) / log(alink / offset)));
130117632Sharti}
131117632Sharti
132117632Sharti/*
133117632Sharti * Convert log to cell rate
134117632Sharti */
135117632Shartistatic double
136117632Shartilog2cps(u_int alink, u_int lg)
137117632Sharti{
138117632Sharti	return (alink / pow(alink / offset,
139117632Sharti	    (double)(tsize - lg - 1) / (tsize - 1)));
140117632Sharti}
141117632Sharti
142117632Sharti/*
143117632Sharti * Convert a double to an internal scaled double
144117632Sharti */
145117632Shartistatic u_int
146117632Shartid2ifp(double fp)
147117632Sharti{
148117632Sharti	fp_rnd_t r;
149117632Sharti	u_int s, ifp;
150117632Sharti
151117632Sharti	fp *= (1 << 16);
152117632Sharti
153117632Sharti	r = fpsetround(FP_RN);
154117632Sharti	ifp = (u_int)rint(fp);
155117632Sharti	fpsetround(r);
156117632Sharti
157117632Sharti	s = 0;
158117632Sharti	while (ifp >= 1024) {
159117632Sharti		s++;
160117632Sharti		ifp >>= 1;
161117632Sharti	}
162117632Sharti	return ((s << 10) | (ifp));
163117632Sharti}
164117632Sharti
165117632Sharti/*
166117632Sharti * Convert internal scaled float to double
167117632Sharti */
168117632Shartistatic double
169117632Shartiifp2d(u_int p)
170117632Sharti{
171117632Sharti	return ((p & 0x3ff) * (1 << ((p >> 10) & 0xf)) / 65536.0);
172117632Sharti}
173117632Sharti
174117632Sharti/*
175117632Sharti * Generate log to rate conversion table
176117632Sharti */
177117632Shartistatic void
178117632Shartigen_log2rate(u_int alink)
179117632Sharti{
180117632Sharti	u_int i, iinterval, atmf, n, nrm;
181117632Sharti	double rate, interval, xinterval, cps, xcps;
182117632Sharti
183117632Sharti	for (i = 0; i < 256; i++) {
184117632Sharti		/* get the desired rate */
185117632Sharti		rate = alink / pow(alink / offset,
186117632Sharti		    (double)(tsize - i - 1) / (tsize - 1));
187117632Sharti
188117632Sharti		/* convert this to an interval */
189117632Sharti		interval = alink / rate;
190117632Sharti
191117632Sharti		/* make the internal form of this interval, be sure to
192117632Sharti		 * round down */
193117632Sharti		iinterval = d2interval(interval);
194117632Sharti
195117632Sharti		/* now convert back */
196117632Sharti		xinterval = interval2d(iinterval);
197117632Sharti
198117632Sharti		/* make a cps from this interval */
199117632Sharti		cps = alink / xinterval;
200117632Sharti
201117632Sharti		/* convert this to its ATM forum format */
202117632Sharti		atmf = cps2atmf(cps);
203117632Sharti
204117632Sharti		/* and back */
205117632Sharti		xcps = atmf2cps(atmf);
206117632Sharti
207117632Sharti		/* decide on NRM */
208117632Sharti		if (xcps < 40.0) {
209117632Sharti			nrm = 0;
210117632Sharti			n = 3;
211117632Sharti		} else if (xcps < 80.0) {
212117632Sharti			nrm = 1;
213117632Sharti			n = 4;
214117632Sharti		} else if (xcps < 160.0) {
215117632Sharti			nrm = 2;
216117632Sharti			n = 8;
217117632Sharti		} else if (xcps < 320.0) {
218117632Sharti			nrm = 3;
219117632Sharti			n = 16;
220117632Sharti		} else {
221117632Sharti			nrm = 4;
222117632Sharti			n = 32;
223117632Sharti		}
224117632Sharti
225117632Sharti		/* print */
226117632Sharti		if (verbose)
227117632Sharti			printf(" 0x%08x, /* %03u: cps=%f nrm=%u int=%f */\n",
228117632Sharti			    (atmf << 17) | (nrm << 14) | iinterval, i,
229117632Sharti			    xcps, n, xinterval);
230117632Sharti		else
231117632Sharti			printf("0x%08x,\n", (atmf << 17) | (nrm << 14) |
232117632Sharti			    iinterval);
233117632Sharti	}
234117632Sharti}
235117632Sharti
236117632Sharti/*
237117632Sharti * Generate rate to log conversion table
238117632Sharti */
239117632Shartistatic void
240117632Shartigen_rate2log(u_int alink)
241117632Sharti{
242117632Sharti	u_int i, atmf, val, ilcr;
243117632Sharti	double cps, lcr;
244117632Sharti	fp_rnd_t r;
245117632Sharti
246117632Sharti	val = 0;
247117632Sharti	for (i = 0; i < 512; i++) {
248117632Sharti		/* make ATM Forum CPS from index */
249117632Sharti		atmf = (((i & 0x1f0) >> 4) << 9) |
250117632Sharti		    ((i & 0xf) << 5) | (1 << 14);
251117632Sharti
252117632Sharti		/* make cps */
253117632Sharti		cps = atmf2cps(atmf);
254117632Sharti
255117632Sharti		/* convert to log */
256117632Sharti		lcr = cps2log(alink, cps);
257117632Sharti
258117632Sharti		r = fpsetround(FP_RN);
259117632Sharti		ilcr = (u_int)rint(lcr);
260117632Sharti		fpsetround(r);
261117632Sharti
262117632Sharti		/* put together */
263117632Sharti		val |= ilcr << (8 * (i % 4));
264117632Sharti
265117632Sharti		/* print */
266117632Sharti		if (i % 4 == 3) {
267117632Sharti			if (verbose)
268117632Sharti				printf(" 0x%08x,\t", val);
269117632Sharti			else
270117632Sharti				printf("0x%08x,\n", val);
271117632Sharti			val = 0;
272117632Sharti		} else if (verbose)
273117632Sharti			printf("\t\t");
274117632Sharti		if (verbose)
275117632Sharti			printf("/* %03u: %f -> %f */\n", i,
276117632Sharti			    cps, log2cps(alink, ilcr));
277117632Sharti	}
278117632Sharti}
279117632Sharti
280117632Sharti/*
281117632Sharti * Generate one entry into the global table
282117632Sharti */
283117632Shartistatic void
284117632Shartigen_glob_entry(u_int alink, u_int fill, u_int ci, u_int ni)
285117632Sharti{
286117632Sharti	if (verbose)
287117632Sharti		printf("  0x%08x,	/* %2u/32 %8.6f, %6u, ci=%u, ni=%u */\n",
288117632Sharti		    cps2atmf(alink * fill / 32.0) | (ci << 17) | (ni << 16),
289117632Sharti		    fill, fill / 32.0, alink * fill / 32, ci, ni);
290117632Sharti	else
291117632Sharti		printf("0x%08x,\n",
292117632Sharti		    cps2atmf(alink * fill / 32.0) | (ci << 17) | (ni << 16));
293117632Sharti}
294117632Sharti
295117632Sharti/*
296117632Sharti * Generate global parameter table
297117632Sharti */
298117632Shartistatic void
299117632Shartigen_glob(u_int alink)
300117632Sharti{
301117632Sharti	u_int i;
302117632Sharti
303117632Sharti	gen_glob_entry(alink, 32, 0, 0);
304117632Sharti	gen_glob_entry(alink, 16, 0, 0);
305117632Sharti	gen_glob_entry(alink,  8, 0, 1);
306117632Sharti	gen_glob_entry(alink,  4, 0, 1);
307117632Sharti	gen_glob_entry(alink,  2, 1, 1);
308117632Sharti	gen_glob_entry(alink,  1, 1, 1);
309117632Sharti	gen_glob_entry(alink,  0, 1, 1);
310117632Sharti	gen_glob_entry(alink,  0, 1, 1);
311117632Sharti
312117632Sharti	for (i = 0; i < tsize/2 - 8; i++) {
313117632Sharti		if (i % 16 == 0)
314117632Sharti			printf(" ");
315117632Sharti		printf(" 0,");
316117632Sharti		if (i % 16 == 15)
317117632Sharti			printf("\n");
318117632Sharti	}
319117632Sharti	printf("\n");
320117632Sharti}
321117632Sharti
322117632Sharti/*
323117632Sharti * Generate additive rate increase tables
324117632Sharti */
325117632Shartistatic void
326117632Shartigen_air(u_int alink)
327117632Sharti{
328117632Sharti	u_int t, i;
329117632Sharti	double diff;	/* cell rate to increase by */
330117632Sharti	double cps;
331117632Sharti	double add;
332117632Sharti	u_int val, a;
333117632Sharti
334117632Sharti	for (t = 0; t < ndtables; t++) {
335117632Sharti		diff = (double)alink / (1 << t);
336117632Sharti		printf("/* AIR %u: diff=%f */\n", t, diff);
337117632Sharti		val = 0;
338117632Sharti		for (i = 0; i < tsize; i++) {
339117632Sharti			cps = log2cps(alink, i);
340117632Sharti			cps += diff;
341117632Sharti			if (cps > alink)
342117632Sharti				cps = alink;
343117632Sharti
344117632Sharti			add = cps2log(alink, cps) - i;
345117632Sharti
346117632Sharti			a = d2ifp(add);
347117632Sharti
348117632Sharti			if (i % 2) {
349117632Sharti				val |= a << 16;
350117632Sharti				if (verbose)
351117632Sharti					printf("  0x%08x,\t", val);
352117632Sharti				else
353117632Sharti					printf("0x%08x,\n", val);
354117632Sharti			} else {
355117632Sharti				val = a;
356117632Sharti				if (verbose)
357117632Sharti					printf("\t\t");
358117632Sharti			}
359117632Sharti			if (verbose)
360117632Sharti				printf("/* %3u: %f */\n", i, ifp2d(add));
361117632Sharti		}
362117632Sharti	}
363117632Sharti}
364117632Sharti
365117632Sharti/*
366117632Sharti * Generate rate decrease table
367117632Sharti */
368117632Shartistatic void
369117632Shartigen_rdf(u_int alink)
370117632Sharti{
371117632Sharti	double d;
372117632Sharti	u_int t, i, f, val, diff;
373117632Sharti
374117632Sharti	for (t = 0; t < ndtables; t++) {
375117632Sharti		/* compute the log index difference */
376117632Sharti		if (t == 0) {
377117632Sharti			d = tsize - 1;
378117632Sharti		} else {
379117632Sharti			f = 1 << t;
380117632Sharti			d = (tsize - 1) / log(alink / offset);
381117632Sharti			d *= log((double)f / (f - 1));
382117632Sharti		}
383117632Sharti		printf(" /* RDF %u: 1/%u: %f */\n", t, 1 << t, d);
384117632Sharti		val = 0;
385117632Sharti		for (i = 0; i < tsize; i++) {
386117632Sharti			if (i < d)
387117632Sharti				diff = d2ifp(i);
388117632Sharti			else
389117632Sharti				diff = d2ifp(d);
390117632Sharti			if (i % 2) {
391117632Sharti				val |= diff << 16;
392117632Sharti				if (verbose)
393117632Sharti					printf("  0x%08x,\t", val);
394117632Sharti				else
395117632Sharti					printf("0x%08x,\n", val);
396117632Sharti			} else {
397117632Sharti				val = diff;
398117632Sharti				if (verbose)
399117632Sharti					printf("\t\t");
400117632Sharti			}
401117632Sharti			if (verbose)
402117632Sharti				printf("/* %3u: %f */\n", i, ifp2d(diff));
403117632Sharti		}
404117632Sharti	}
405117632Sharti}
406117632Sharti
407117632Sharti/*
408117632Sharti * Create all the tables for a given link cell rate and link bit rate.
409117632Sharti * The link bit rate is only used to name the table.
410117632Sharti */
411117632Shartistatic void
412117632Shartigen_tables(u_int alink, u_int mbps)
413117632Sharti{
414117632Sharti	printf("\n");
415117632Sharti	printf("/*\n");
416117632Sharti	printf(" * Tables for %ucps and %uMbps\n", alink, mbps);
417117632Sharti	printf(" */\n");
418117632Sharti	printf("const uint32_t patm_rtables%u[128 * (4 + 2 * %u)] = {\n",
419117632Sharti	    mbps, ndtables);
420117632Sharti
421117632Sharti	gen_log2rate(alink);
422117632Sharti	gen_rate2log(alink);
423117632Sharti	gen_glob(alink);
424117632Sharti	gen_air(alink);
425117632Sharti	gen_rdf(alink);
426117632Sharti
427117632Sharti	printf("};\n");
428117632Sharti}
429117632Sharti
430117632Shartiint
431117632Shartimain(int argc, char *argv[])
432117632Sharti{
433117632Sharti	int opt;
434117632Sharti
435117632Sharti	while ((opt = getopt(argc, argv, "v")) != -1)
436117632Sharti		switch (opt) {
437117632Sharti
438117632Sharti		  case 'v':
439117632Sharti			verbose = 1;
440117632Sharti			break;
441117632Sharti		}
442117632Sharti
443117632Sharti	printf("/*\n");
444117632Sharti	printf(" * This file was generated by `%s'\n", argv[0]);
445117632Sharti	printf(" */\n");
446117632Sharti	printf("\n");
447117632Sharti	printf("#include <sys/cdefs.h>\n");
448117632Sharti	printf("__FBSDID(\"$FreeBSD$\");\n");
449117632Sharti	printf("\n");
450117632Sharti	printf("#include <sys/types.h>\n");
451117632Sharti	printf("\n");
452117632Sharti	printf("const u_int patm_rtables_size = 128 * (4 + 2 * %u);\n",
453117632Sharti	    ndtables);
454117632Sharti	printf("const u_int patm_rtables_ntab = %u;\n", ndtables);
455117632Sharti	gen_tables(352768, 155);
456117632Sharti	gen_tables( 59259,  25);
457117632Sharti	return (0);
458117632Sharti}
459