459 lines
9.2 KiB
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);
|
|
}
|