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: releng/11.0/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 */ 43static int verbose; 44 45/* number of table entries */ 46static const u_int tsize = 256; 47 48/* number of rate difference tables to create */ 49static const u_int ndtables = 16; 50 51/* cell rate offset for log 0 */ 52static const double offset = 10.0; 53 54/* 55 * Make an internal form of the interval and be sure to round down. 56 */ 57static u_int 58d2interval(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 */ 78static double 79interval2d(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 */ 87static u_int 88cps2atmf(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 */ 111static double 112atmf2cps(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 */ 121static double 122cps2log(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 */ 135static double 136log2cps(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 */ 145static u_int 146d2ifp(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 */ 168static double 169ifp2d(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 */ 177static void 178gen_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 */ 239static void 240gen_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 */ 283static void 284gen_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 */ 298static void 299gen_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 */ 325static void 326gen_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 */ 368static void 369gen_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 */ 411static void 412gen_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 430int 431main(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: releng/11.0/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