/*- * Copyright (c) 2003 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Author: Hartmut Brandt * * This program is used to generate the different rate tables for the IDT77252 * driver. The generated tables are slightly different from those in the * IDT manual. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include /* verbosity flag */ static int verbose; /* number of table entries */ static const u_int tsize = 256; /* number of rate difference tables to create */ static const u_int ndtables = 16; /* cell rate offset for log 0 */ static const double offset = 10.0; /* * Make an internal form of the interval and be sure to round down. */ static u_int d2interval(double d) { fp_rnd_t r; u_int s, id; r = fpsetround(FP_RZ); id = (u_int)rint(32 * d); fpsetround(r); s = 0; while (id >= 32 * 32) { s++; id >>= 1; } return ((s << 10) | (id)); } /* * Convert an internal interval back to a real one. */ static double interval2d(u_int id) { return ((1 << ((id >> 10) & 0xf)) * ((id & 0x3ff) / 32.0)); } /* * Convert double to ATM-Forum format. Make sure to round up. */ static u_int cps2atmf(double cps) { fp_rnd_t r; u_int s, id; if (cps < 1.0) return (0); s = 0; while (cps >= 2.0) { s++; cps /= 2; } r = fpsetround(FP_RP); id = (u_int)rint(512 * cps); fpsetround(r); return ((1 << 14) | (s << 9) | (id & 0x1ff)); } /* * Convert ATM forum format to double */ static double atmf2cps(u_int atmf) { return (((atmf >> 14) & 1) * (1 << ((atmf >> 9) & 0x1f)) * ((512 + (atmf & 0x1ff)) / 512.0)); } /* * A cell rate to the logarithmic one */ static double cps2log(u_int alink, double lg) { if (lg <= offset) return (0); if (lg >= alink) return (tsize - 1); return ((tsize - 1) * (1 - log(alink / lg) / log(alink / offset))); } /* * Convert log to cell rate */ static double log2cps(u_int alink, u_int lg) { return (alink / pow(alink / offset, (double)(tsize - lg - 1) / (tsize - 1))); } /* * Convert a double to an internal scaled double */ static u_int d2ifp(double fp) { fp_rnd_t r; u_int s, ifp; fp *= (1 << 16); r = fpsetround(FP_RN); ifp = (u_int)rint(fp); fpsetround(r); s = 0; while (ifp >= 1024) { s++; ifp >>= 1; } return ((s << 10) | (ifp)); } /* * Convert internal scaled float to double */ static double ifp2d(u_int p) { return ((p & 0x3ff) * (1 << ((p >> 10) & 0xf)) / 65536.0); } /* * Generate log to rate conversion table */ static void gen_log2rate(u_int alink) { u_int i, iinterval, atmf, n, nrm; double rate, interval, xinterval, cps, xcps; for (i = 0; i < 256; i++) { /* get the desired rate */ rate = alink / pow(alink / offset, (double)(tsize - i - 1) / (tsize - 1)); /* convert this to an interval */ interval = alink / rate; /* make the internal form of this interval, be sure to * round down */ iinterval = d2interval(interval); /* now convert back */ xinterval = interval2d(iinterval); /* make a cps from this interval */ cps = alink / xinterval; /* convert this to its ATM forum format */ atmf = cps2atmf(cps); /* and back */ xcps = atmf2cps(atmf); /* decide on NRM */ if (xcps < 40.0) { nrm = 0; n = 3; } else if (xcps < 80.0) { nrm = 1; n = 4; } else if (xcps < 160.0) { nrm = 2; n = 8; } else if (xcps < 320.0) { nrm = 3; n = 16; } else { nrm = 4; n = 32; } /* print */ if (verbose) printf(" 0x%08x, /* %03u: cps=%f nrm=%u int=%f */\n", (atmf << 17) | (nrm << 14) | iinterval, i, xcps, n, xinterval); else printf("0x%08x,\n", (atmf << 17) | (nrm << 14) | iinterval); } } /* * Generate rate to log conversion table */ static void gen_rate2log(u_int alink) { u_int i, atmf, val, ilcr; double cps, lcr; fp_rnd_t r; val = 0; for (i = 0; i < 512; i++) { /* make ATM Forum CPS from index */ atmf = (((i & 0x1f0) >> 4) << 9) | ((i & 0xf) << 5) | (1 << 14); /* make cps */ cps = atmf2cps(atmf); /* convert to log */ lcr = cps2log(alink, cps); r = fpsetround(FP_RN); ilcr = (u_int)rint(lcr); fpsetround(r); /* put together */ val |= ilcr << (8 * (i % 4)); /* print */ if (i % 4 == 3) { if (verbose) printf(" 0x%08x,\t", val); else printf("0x%08x,\n", val); val = 0; } else if (verbose) printf("\t\t"); if (verbose) printf("/* %03u: %f -> %f */\n", i, cps, log2cps(alink, ilcr)); } } /* * Generate one entry into the global table */ static void gen_glob_entry(u_int alink, u_int fill, u_int ci, u_int ni) { if (verbose) printf(" 0x%08x, /* %2u/32 %8.6f, %6u, ci=%u, ni=%u */\n", cps2atmf(alink * fill / 32.0) | (ci << 17) | (ni << 16), fill, fill / 32.0, alink * fill / 32, ci, ni); else printf("0x%08x,\n", cps2atmf(alink * fill / 32.0) | (ci << 17) | (ni << 16)); } /* * Generate global parameter table */ static void gen_glob(u_int alink) { u_int i; gen_glob_entry(alink, 32, 0, 0); gen_glob_entry(alink, 16, 0, 0); gen_glob_entry(alink, 8, 0, 1); gen_glob_entry(alink, 4, 0, 1); gen_glob_entry(alink, 2, 1, 1); gen_glob_entry(alink, 1, 1, 1); gen_glob_entry(alink, 0, 1, 1); gen_glob_entry(alink, 0, 1, 1); for (i = 0; i < tsize/2 - 8; i++) { if (i % 16 == 0) printf(" "); printf(" 0,"); if (i % 16 == 15) printf("\n"); } printf("\n"); } /* * Generate additive rate increase tables */ static void gen_air(u_int alink) { u_int t, i; double diff; /* cell rate to increase by */ double cps; double add; u_int val, a; for (t = 0; t < ndtables; t++) { diff = (double)alink / (1 << t); printf("/* AIR %u: diff=%f */\n", t, diff); val = 0; for (i = 0; i < tsize; i++) { cps = log2cps(alink, i); cps += diff; if (cps > alink) cps = alink; add = cps2log(alink, cps) - i; a = d2ifp(add); if (i % 2) { val |= a << 16; if (verbose) printf(" 0x%08x,\t", val); else printf("0x%08x,\n", val); } else { val = a; if (verbose) printf("\t\t"); } if (verbose) printf("/* %3u: %f */\n", i, ifp2d(add)); } } } /* * Generate rate decrease table */ static void gen_rdf(u_int alink) { double d; u_int t, i, f, val, diff; for (t = 0; t < ndtables; t++) { /* compute the log index difference */ if (t == 0) { d = tsize - 1; } else { f = 1 << t; d = (tsize - 1) / log(alink / offset); d *= log((double)f / (f - 1)); } printf(" /* RDF %u: 1/%u: %f */\n", t, 1 << t, d); val = 0; for (i = 0; i < tsize; i++) { if (i < d) diff = d2ifp(i); else diff = d2ifp(d); if (i % 2) { val |= diff << 16; if (verbose) printf(" 0x%08x,\t", val); else printf("0x%08x,\n", val); } else { val = diff; if (verbose) printf("\t\t"); } if (verbose) printf("/* %3u: %f */\n", i, ifp2d(diff)); } } } /* * Create all the tables for a given link cell rate and link bit rate. * The link bit rate is only used to name the table. */ static void gen_tables(u_int alink, u_int mbps) { printf("\n"); printf("/*\n"); printf(" * Tables for %ucps and %uMbps\n", alink, mbps); printf(" */\n"); printf("const uint32_t patm_rtables%u[128 * (4 + 2 * %u)] = {\n", mbps, ndtables); gen_log2rate(alink); gen_rate2log(alink); gen_glob(alink); gen_air(alink); gen_rdf(alink); printf("};\n"); } int main(int argc, char *argv[]) { int opt; while ((opt = getopt(argc, argv, "v")) != -1) switch (opt) { case 'v': verbose = 1; break; } printf("/*\n"); printf(" * This file was generated by `%s'\n", argv[0]); printf(" */\n"); printf("\n"); printf("#include \n"); printf("__FBSDID(\"$FreeBSD$\");\n"); printf("\n"); printf("#include \n"); printf("\n"); printf("const u_int patm_rtables_size = 128 * (4 + 2 * %u);\n", ndtables); printf("const u_int patm_rtables_ntab = %u;\n", ndtables); gen_tables(352768, 155); gen_tables( 59259, 25); return (0); }