1 /*-
2  * Copyright (c) 2003
3  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  * 	All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * Author: Hartmut Brandt <harti@freebsd.org>
28  *
29  * This program is used to generate the different rate tables for the IDT77252
30  * driver. The generated tables are slightly different from those in the
31  * IDT manual.
32  */
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: stable/9/sys/dev/patm/genrtab/genrtab.c 139749 2005-01-06 01:43:34Z imp $");
35 
36 #include <sys/types.h>
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <math.h>
40 #include <ieeefp.h>
41 
42 /* verbosity flag */
43 static int verbose;
44 
45 /* number of table entries */
46 static const u_int tsize = 256;
47 
48 /* number of rate difference tables to create */
49 static const u_int ndtables = 16;
50 
51 /* cell rate offset for log 0 */
52 static const double offset = 10.0;
53 
54 /*
55  * Make an internal form of the interval and be sure to round down.
56  */
57 static u_int
d2interval(double d)58 d2interval(double d)
59 {
60 	fp_rnd_t r;
61 	u_int s, id;
62 
63 	r = fpsetround(FP_RZ);
64 	id = (u_int)rint(32 * d);
65 	fpsetround(r);
66 
67 	s = 0;
68 	while (id >= 32 * 32) {
69 		s++;
70 		id >>= 1;
71 	}
72 	return ((s << 10) | (id));
73 }
74 
75 /*
76  * Convert an internal interval back to a real one.
77  */
78 static double
interval2d(u_int id)79 interval2d(u_int id)
80 {
81 	return ((1 << ((id >> 10) & 0xf)) * ((id & 0x3ff) / 32.0));
82 }
83 
84 /*
85  * Convert double to ATM-Forum format. Make sure to round up.
86  */
87 static u_int
cps2atmf(double cps)88 cps2atmf(double cps)
89 {
90 	fp_rnd_t r;
91 	u_int s, id;
92 
93 	if (cps < 1.0)
94 		return (0);
95 
96 	s = 0;
97 	while (cps >= 2.0) {
98 		s++;
99 		cps /= 2;
100 	}
101 	r = fpsetround(FP_RP);
102 	id = (u_int)rint(512 * cps);
103 	fpsetround(r);
104 
105 	return ((1 << 14) | (s << 9) | (id & 0x1ff));
106 }
107 
108 /*
109  * Convert ATM forum format to double
110  */
111 static double
atmf2cps(u_int atmf)112 atmf2cps(u_int atmf)
113 {
114 	return (((atmf >> 14) & 1) * (1 << ((atmf >> 9) & 0x1f)) *
115 	    ((512 + (atmf & 0x1ff)) / 512.0));
116 }
117 
118 /*
119  * A cell rate to the logarithmic one
120  */
121 static double
cps2log(u_int alink,double lg)122 cps2log(u_int alink, double lg)
123 {
124 	if (lg <= offset)
125 		return (0);
126 	if (lg >= alink)
127 		return (tsize - 1);
128 
129 	return ((tsize - 1) * (1 - log(alink / lg) / log(alink / offset)));
130 }
131 
132 /*
133  * Convert log to cell rate
134  */
135 static double
log2cps(u_int alink,u_int lg)136 log2cps(u_int alink, u_int lg)
137 {
138 	return (alink / pow(alink / offset,
139 	    (double)(tsize - lg - 1) / (tsize - 1)));
140 }
141 
142 /*
143  * Convert a double to an internal scaled double
144  */
145 static u_int
d2ifp(double fp)146 d2ifp(double fp)
147 {
148 	fp_rnd_t r;
149 	u_int s, ifp;
150 
151 	fp *= (1 << 16);
152 
153 	r = fpsetround(FP_RN);
154 	ifp = (u_int)rint(fp);
155 	fpsetround(r);
156 
157 	s = 0;
158 	while (ifp >= 1024) {
159 		s++;
160 		ifp >>= 1;
161 	}
162 	return ((s << 10) | (ifp));
163 }
164 
165 /*
166  * Convert internal scaled float to double
167  */
168 static double
ifp2d(u_int p)169 ifp2d(u_int p)
170 {
171 	return ((p & 0x3ff) * (1 << ((p >> 10) & 0xf)) / 65536.0);
172 }
173 
174 /*
175  * Generate log to rate conversion table
176  */
177 static void
gen_log2rate(u_int alink)178 gen_log2rate(u_int alink)
179 {
180 	u_int i, iinterval, atmf, n, nrm;
181 	double rate, interval, xinterval, cps, xcps;
182 
183 	for (i = 0; i < 256; i++) {
184 		/* get the desired rate */
185 		rate = alink / pow(alink / offset,
186 		    (double)(tsize - i - 1) / (tsize - 1));
187 
188 		/* convert this to an interval */
189 		interval = alink / rate;
190 
191 		/* make the internal form of this interval, be sure to
192 		 * round down */
193 		iinterval = d2interval(interval);
194 
195 		/* now convert back */
196 		xinterval = interval2d(iinterval);
197 
198 		/* make a cps from this interval */
199 		cps = alink / xinterval;
200 
201 		/* convert this to its ATM forum format */
202 		atmf = cps2atmf(cps);
203 
204 		/* and back */
205 		xcps = atmf2cps(atmf);
206 
207 		/* decide on NRM */
208 		if (xcps < 40.0) {
209 			nrm = 0;
210 			n = 3;
211 		} else if (xcps < 80.0) {
212 			nrm = 1;
213 			n = 4;
214 		} else if (xcps < 160.0) {
215 			nrm = 2;
216 			n = 8;
217 		} else if (xcps < 320.0) {
218 			nrm = 3;
219 			n = 16;
220 		} else {
221 			nrm = 4;
222 			n = 32;
223 		}
224 
225 		/* print */
226 		if (verbose)
227 			printf(" 0x%08x, /* %03u: cps=%f nrm=%u int=%f */\n",
228 			    (atmf << 17) | (nrm << 14) | iinterval, i,
229 			    xcps, n, xinterval);
230 		else
231 			printf("0x%08x,\n", (atmf << 17) | (nrm << 14) |
232 			    iinterval);
233 	}
234 }
235 
236 /*
237  * Generate rate to log conversion table
238  */
239 static void
gen_rate2log(u_int alink)240 gen_rate2log(u_int alink)
241 {
242 	u_int i, atmf, val, ilcr;
243 	double cps, lcr;
244 	fp_rnd_t r;
245 
246 	val = 0;
247 	for (i = 0; i < 512; i++) {
248 		/* make ATM Forum CPS from index */
249 		atmf = (((i & 0x1f0) >> 4) << 9) |
250 		    ((i & 0xf) << 5) | (1 << 14);
251 
252 		/* make cps */
253 		cps = atmf2cps(atmf);
254 
255 		/* convert to log */
256 		lcr = cps2log(alink, cps);
257 
258 		r = fpsetround(FP_RN);
259 		ilcr = (u_int)rint(lcr);
260 		fpsetround(r);
261 
262 		/* put together */
263 		val |= ilcr << (8 * (i % 4));
264 
265 		/* print */
266 		if (i % 4 == 3) {
267 			if (verbose)
268 				printf(" 0x%08x,\t", val);
269 			else
270 				printf("0x%08x,\n", val);
271 			val = 0;
272 		} else if (verbose)
273 			printf("\t\t");
274 		if (verbose)
275 			printf("/* %03u: %f -> %f */\n", i,
276 			    cps, log2cps(alink, ilcr));
277 	}
278 }
279 
280 /*
281  * Generate one entry into the global table
282  */
283 static void
gen_glob_entry(u_int alink,u_int fill,u_int ci,u_int ni)284 gen_glob_entry(u_int alink, u_int fill, u_int ci, u_int ni)
285 {
286 	if (verbose)
287 		printf("  0x%08x,	/* %2u/32 %8.6f, %6u, ci=%u, ni=%u */\n",
288 		    cps2atmf(alink * fill / 32.0) | (ci << 17) | (ni << 16),
289 		    fill, fill / 32.0, alink * fill / 32, ci, ni);
290 	else
291 		printf("0x%08x,\n",
292 		    cps2atmf(alink * fill / 32.0) | (ci << 17) | (ni << 16));
293 }
294 
295 /*
296  * Generate global parameter table
297  */
298 static void
gen_glob(u_int alink)299 gen_glob(u_int alink)
300 {
301 	u_int i;
302 
303 	gen_glob_entry(alink, 32, 0, 0);
304 	gen_glob_entry(alink, 16, 0, 0);
305 	gen_glob_entry(alink,  8, 0, 1);
306 	gen_glob_entry(alink,  4, 0, 1);
307 	gen_glob_entry(alink,  2, 1, 1);
308 	gen_glob_entry(alink,  1, 1, 1);
309 	gen_glob_entry(alink,  0, 1, 1);
310 	gen_glob_entry(alink,  0, 1, 1);
311 
312 	for (i = 0; i < tsize/2 - 8; i++) {
313 		if (i % 16 == 0)
314 			printf(" ");
315 		printf(" 0,");
316 		if (i % 16 == 15)
317 			printf("\n");
318 	}
319 	printf("\n");
320 }
321 
322 /*
323  * Generate additive rate increase tables
324  */
325 static void
gen_air(u_int alink)326 gen_air(u_int alink)
327 {
328 	u_int t, i;
329 	double diff;	/* cell rate to increase by */
330 	double cps;
331 	double add;
332 	u_int val, a;
333 
334 	for (t = 0; t < ndtables; t++) {
335 		diff = (double)alink / (1 << t);
336 		printf("/* AIR %u: diff=%f */\n", t, diff);
337 		val = 0;
338 		for (i = 0; i < tsize; i++) {
339 			cps = log2cps(alink, i);
340 			cps += diff;
341 			if (cps > alink)
342 				cps = alink;
343 
344 			add = cps2log(alink, cps) - i;
345 
346 			a = d2ifp(add);
347 
348 			if (i % 2) {
349 				val |= a << 16;
350 				if (verbose)
351 					printf("  0x%08x,\t", val);
352 				else
353 					printf("0x%08x,\n", val);
354 			} else {
355 				val = a;
356 				if (verbose)
357 					printf("\t\t");
358 			}
359 			if (verbose)
360 				printf("/* %3u: %f */\n", i, ifp2d(add));
361 		}
362 	}
363 }
364 
365 /*
366  * Generate rate decrease table
367  */
368 static void
gen_rdf(u_int alink)369 gen_rdf(u_int alink)
370 {
371 	double d;
372 	u_int t, i, f, val, diff;
373 
374 	for (t = 0; t < ndtables; t++) {
375 		/* compute the log index difference */
376 		if (t == 0) {
377 			d = tsize - 1;
378 		} else {
379 			f = 1 << t;
380 			d = (tsize - 1) / log(alink / offset);
381 			d *= log((double)f / (f - 1));
382 		}
383 		printf(" /* RDF %u: 1/%u: %f */\n", t, 1 << t, d);
384 		val = 0;
385 		for (i = 0; i < tsize; i++) {
386 			if (i < d)
387 				diff = d2ifp(i);
388 			else
389 				diff = d2ifp(d);
390 			if (i % 2) {
391 				val |= diff << 16;
392 				if (verbose)
393 					printf("  0x%08x,\t", val);
394 				else
395 					printf("0x%08x,\n", val);
396 			} else {
397 				val = diff;
398 				if (verbose)
399 					printf("\t\t");
400 			}
401 			if (verbose)
402 				printf("/* %3u: %f */\n", i, ifp2d(diff));
403 		}
404 	}
405 }
406 
407 /*
408  * Create all the tables for a given link cell rate and link bit rate.
409  * The link bit rate is only used to name the table.
410  */
411 static void
gen_tables(u_int alink,u_int mbps)412 gen_tables(u_int alink, u_int mbps)
413 {
414 	printf("\n");
415 	printf("/*\n");
416 	printf(" * Tables for %ucps and %uMbps\n", alink, mbps);
417 	printf(" */\n");
418 	printf("const uint32_t patm_rtables%u[128 * (4 + 2 * %u)] = {\n",
419 	    mbps, ndtables);
420 
421 	gen_log2rate(alink);
422 	gen_rate2log(alink);
423 	gen_glob(alink);
424 	gen_air(alink);
425 	gen_rdf(alink);
426 
427 	printf("};\n");
428 }
429 
430 int
main(int argc,char * argv[])431 main(int argc, char *argv[])
432 {
433 	int opt;
434 
435 	while ((opt = getopt(argc, argv, "v")) != -1)
436 		switch (opt) {
437 
438 		  case 'v':
439 			verbose = 1;
440 			break;
441 		}
442 
443 	printf("/*\n");
444 	printf(" * This file was generated by `%s'\n", argv[0]);
445 	printf(" */\n");
446 	printf("\n");
447 	printf("#include <sys/cdefs.h>\n");
448 	printf("__FBSDID(\"$FreeBSD: stable/9/sys/dev/patm/genrtab/genrtab.c 139749 2005-01-06 01:43:34Z imp $\");\n");
449 	printf("\n");
450 	printf("#include <sys/types.h>\n");
451 	printf("\n");
452 	printf("const u_int patm_rtables_size = 128 * (4 + 2 * %u);\n",
453 	    ndtables);
454 	printf("const u_int patm_rtables_ntab = %u;\n", ndtables);
455 	gen_tables(352768, 155);
456 	gen_tables( 59259,  25);
457 	return (0);
458 }
459