freebsd-nq/sys/dev/patm/genrtab/genrtab.c

459 lines
9.2 KiB
C

/*-
* 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 <harti@freebsd.org>
*
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <ieeefp.h>
/* 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 <sys/cdefs.h>\n");
printf("__FBSDID(\"$FreeBSD$\");\n");
printf("\n");
printf("#include <sys/types.h>\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);
}