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