446 lines
12 KiB
C
446 lines
12 KiB
C
/* rtrTech.c -
|
|
*
|
|
* This file processes the part of technology files that
|
|
* provides information to the router. It sets up information
|
|
* giving, for example, the layers to use for routing, their
|
|
* widths, and so on.
|
|
*
|
|
* *********************************************************************
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
* * software and its documentation for any purpose and without *
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
* * notice appear in all copies. The University of California *
|
|
* * makes no representations about the suitability of this *
|
|
* * software for any purpose. It is provided "as is" without *
|
|
* * express or implied warranty. Export of this software outside *
|
|
* * of the United States of America may require an export license. *
|
|
* *********************************************************************
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/router/rtrTech.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "utils/magic.h"
|
|
#include "utils/utils.h"
|
|
#include "utils/geometry.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/hash.h"
|
|
#include "database/database.h"
|
|
#include "utils/tech.h"
|
|
#include "textio/textio.h"
|
|
#include "windows/windows.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "router/router.h"
|
|
|
|
/* The global routing variables are defined below. See router.h
|
|
* for a description of what they mean.
|
|
*/
|
|
|
|
/* These are used by non-router modules (maybe they shouldn't be?) so */
|
|
/* they are defined in dbwind/DBWdisplay.c, one of the places where */
|
|
/* they are used. */
|
|
|
|
/* int RtrMetalWidth, RtrPolyWidth, RtrContactWidth; */
|
|
|
|
TileType RtrMetalType, RtrPolyType, RtrContactType;
|
|
int RtrContactOffset;
|
|
int RtrMetalSurround, RtrPolySurround;
|
|
int RtrGridSpacing;
|
|
int RtrSubcellSepUp, RtrSubcellSepDown;
|
|
TileTypeBitMask RtrMetalObstacles, RtrPolyObstacles;
|
|
int RtrPaintSepsUp[TT_MAXTYPES], RtrPaintSepsDown[TT_MAXTYPES];
|
|
|
|
/* The arrays below are used to hold the obstacle information separately
|
|
* for the two routing layers. These are used temporarily while reading
|
|
* the technology file, but also used directly by the maze router. Eventually
|
|
* the info is combined and put into RtrPaintSepsUp and RtrPaintSepsDown.
|
|
*/
|
|
|
|
int RtrMetalSeps[TT_MAXTYPES], RtrPolySeps[TT_MAXTYPES];
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* RtrTechInit --
|
|
*
|
|
* This routine is called once just before reading the router
|
|
* section of the technology file.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Initializes the data structures. The main idea is to make
|
|
* things consistent so that if there is an empty router section,
|
|
* the router won't crash if it's invoked (it probably won't
|
|
* generate nice routing, but at least it won't core dump).
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
RtrTechInit()
|
|
{
|
|
int i;
|
|
RtrMetalType = RtrPolyType = RtrContactType = TT_SPACE;
|
|
RtrMetalWidth = RtrPolyWidth = RtrContactWidth = 2;
|
|
RtrContactOffset = 0;
|
|
RtrMetalSurround = 0;
|
|
RtrPolySurround = 0;
|
|
RtrGridSpacing = 4;
|
|
RtrSubcellSepUp = 4;
|
|
RtrSubcellSepDown = 4;
|
|
TTMaskZero(&RtrMetalObstacles);
|
|
TTMaskZero(&RtrPolyObstacles);
|
|
for (i=0; i<TT_MAXTYPES; i++)
|
|
{
|
|
RtrMetalSeps[i] = 0;
|
|
RtrPolySeps[i] = 0;
|
|
RtrPaintSepsUp[i] = 0;
|
|
RtrPaintSepsDown[i] = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* RtrTechLine --
|
|
*
|
|
* This procedure is called once for each line in the router
|
|
* section of the technology file.
|
|
*
|
|
* Results:
|
|
* TRUE result means the line was parse-able. FALSE means the
|
|
* line was so fundamentally bad that Magic should abort after
|
|
* reading the whole technology file.
|
|
*
|
|
* Side effects:
|
|
* Based on the information in the line, overall routing control
|
|
* information is set up.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
bool
|
|
RtrTechLine(sectionName, argc, argv)
|
|
char *sectionName; /* Name of this section. */
|
|
int argc; /* Number of fields on line. */
|
|
char *argv[]; /* Values of fields. */
|
|
{
|
|
TileTypeBitMask mask;
|
|
int type, width, i, distance;
|
|
char **nextArg;
|
|
|
|
if (argc <= 0) return TRUE;
|
|
|
|
/* Look for descriptions of the two routing layers. */
|
|
|
|
if (strcmp(argv[0], "layer1") == 0)
|
|
{
|
|
if (argc < 3)
|
|
{
|
|
wrongNumArgs:
|
|
TechError("Wrong number of arguments in router %s statement.\n",
|
|
argv[0]);
|
|
return TRUE;
|
|
}
|
|
type = DBTechNoisyNameType(argv[1]);
|
|
if (type >= 0) RtrMetalType = type;
|
|
width = atoi(argv[2]);
|
|
if (width <= 0)
|
|
TechError("Layer1 width must be positive; %d is illegal.\n",
|
|
width);
|
|
else RtrMetalWidth = width;
|
|
TTMaskZero(&RtrMetalObstacles);
|
|
argc -= 3;
|
|
nextArg = &(argv[3]);
|
|
while (argc >= 2)
|
|
{
|
|
DBTechNoisyNameMask(*nextArg, &mask);
|
|
distance = atoi(nextArg[1]);
|
|
if (distance < 0)
|
|
{
|
|
TechError("Layer1 obstacle separation must be positive; %d is illegal.\n",
|
|
distance);
|
|
}
|
|
else for (i=0; i<TT_MAXTYPES; i++)
|
|
{
|
|
if (TTMaskHasType(&mask, i))
|
|
{
|
|
/* Raw distances get stored temporarily in RtrMetalSeps.
|
|
* RtrTechFinal will compute the final correct values
|
|
* for RtrPaintSepsUp and RtrPaintSepsDown.
|
|
*/
|
|
if (RtrMetalSeps[i] < distance)
|
|
RtrMetalSeps[i] = distance;
|
|
}
|
|
}
|
|
TTMaskSetMask(&RtrMetalObstacles, &mask);
|
|
argc -= 2;
|
|
nextArg += 2;
|
|
}
|
|
if (argc == 1) goto wrongNumArgs;
|
|
return TRUE;
|
|
}
|
|
|
|
if (strcmp(argv[0], "layer2") == 0)
|
|
{
|
|
if (argc < 3) goto wrongNumArgs;
|
|
type = DBTechNoisyNameType(argv[1]);
|
|
if (type >= 0) RtrPolyType = type;
|
|
width = atoi(argv[2]);
|
|
if (width <= 0)
|
|
TechError("Layer2 width must be positive; %d is illegal.\n",
|
|
width);
|
|
else RtrPolyWidth = width;
|
|
TTMaskZero(&RtrPolyObstacles);
|
|
argc -= 3;
|
|
nextArg = &(argv[3]);
|
|
while (argc >= 2)
|
|
{
|
|
DBTechNoisyNameMask(*nextArg, &mask);
|
|
distance = atoi(nextArg[1]);
|
|
if (distance < 0)
|
|
{
|
|
TechError("Layer2 obstacle separation must be positive: %d is illegal.\n",
|
|
distance);
|
|
}
|
|
else for (i=0; i<TT_MAXTYPES; i++)
|
|
{
|
|
if (TTMaskHasType(&mask, i))
|
|
{
|
|
if (RtrPolySeps[i] < distance)
|
|
RtrPolySeps[i] = distance;
|
|
}
|
|
}
|
|
TTMaskSetMask(&RtrPolyObstacles, &mask);
|
|
argc -= 2;
|
|
nextArg += 2;
|
|
}
|
|
if (argc == 1) goto wrongNumArgs;
|
|
return TRUE;
|
|
}
|
|
|
|
/* Look for contact specification. */
|
|
|
|
if (strcmp(argv[0], "contacts") == 0)
|
|
{
|
|
if ((argc != 3) && (argc != 5)) goto wrongNumArgs;
|
|
type = DBTechNoisyNameType(argv[1]);
|
|
if (type >= 0) RtrContactType = type;
|
|
width = atoi(argv[2]);
|
|
if (width <= 0)
|
|
TechError("Contact width must be positive; %d is illegal.\n",
|
|
width);
|
|
else RtrContactWidth = width;
|
|
RtrContactOffset = 0;
|
|
if (argc == 5)
|
|
{
|
|
if (!StrIsInt(argv[3]))
|
|
TechError("Metal contact surround \"%s\" isn't integral.\n",
|
|
argv[3]);
|
|
else
|
|
{
|
|
RtrMetalSurround = atoi(argv[3]);
|
|
if (RtrMetalSurround < 0)
|
|
{
|
|
TechError("Metal contact surround \"%s\" mustn't be negative.\n", argv[3]);
|
|
RtrMetalSurround = 0;
|
|
}
|
|
}
|
|
if (!StrIsInt(argv[4]))
|
|
TechError("Poly contact surround \"%s\" isn't integral.\n",
|
|
argv[4]);
|
|
else
|
|
{
|
|
RtrPolySurround = atoi(argv[4]);
|
|
if (RtrPolySurround < 0)
|
|
{
|
|
TechError("Poly contact surround \"%s\" mustn't be negative.\n", argv[4]);
|
|
RtrPolySurround = 0;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* Next, look for a gridspacing line. */
|
|
|
|
if (strcmp(argv[0], "gridspacing") == 0)
|
|
{
|
|
if (argc != 2) goto wrongNumArgs;
|
|
i = atoi(argv[1]);
|
|
if (i <= 0)
|
|
TechError("Gridspacing must be positive; %d is illegal.\n", i);
|
|
else RtrGridSpacing = i;
|
|
return TRUE;
|
|
}
|
|
|
|
TechError("Unknown router statement \"%s\".\n", argv[0]);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* RtrTechFinal --
|
|
*
|
|
* Called once at the very end of the router section of the technology
|
|
* file.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Compute the actual subcell and paint separations, based on
|
|
* the technology file information.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
RtrTechFinal()
|
|
{
|
|
int i, above, below;
|
|
|
|
/* Pick a contact offset so that the contacts are more-or-less
|
|
* centered on the routing material. Use the wider routing material
|
|
* to make this decision; otherwise, the material might end up
|
|
* sticking out past the edge of the contact. When rounding, round
|
|
* down (since this works better if the two routing layers are different
|
|
* widths).
|
|
*/
|
|
|
|
i = RtrMetalWidth;
|
|
if (RtrPolyWidth > i) i = RtrPolyWidth;
|
|
RtrContactOffset = - (RtrContactWidth + 1 - i)/2;
|
|
|
|
/* The actual actual distance from a paint layer to a grid line
|
|
* is a combination of how far the paint must be from routing
|
|
* material, and where routing material goes relative to the
|
|
* grid line.
|
|
*/
|
|
|
|
RtrSubcellSepUp = RtrSubcellSepDown = 0;
|
|
|
|
/* Compute how far above and below grid lines the routing layers run,
|
|
* and compensate the obstacle separations accordingly. This is
|
|
* determined by the contact size and location.
|
|
*/
|
|
|
|
above = RtrContactWidth + RtrContactOffset;
|
|
below = - RtrContactOffset;
|
|
|
|
for (i=0; i < TT_MAXTYPES; i++)
|
|
{
|
|
int metal, poly;
|
|
if (TTMaskHasType(&RtrMetalObstacles, i))
|
|
metal = RtrMetalSeps[i] + RtrMetalSurround;
|
|
else metal = 0;
|
|
if (TTMaskHasType(&RtrPolyObstacles, i))
|
|
poly = RtrPolySeps[i] + RtrPolySurround;
|
|
else poly = 0;
|
|
if (metal < poly) metal = poly;
|
|
RtrPaintSepsDown[i] = metal + above;
|
|
RtrPaintSepsUp[i] = metal + below;
|
|
if (RtrPaintSepsDown[i] > RtrSubcellSepDown)
|
|
RtrSubcellSepDown = RtrPaintSepsDown[i];
|
|
if (RtrPaintSepsUp[i] > RtrSubcellSepUp)
|
|
RtrSubcellSepUp = RtrPaintSepsUp[i];
|
|
}
|
|
|
|
#ifdef notdef
|
|
TxPrintf("Routing information:\n");
|
|
TxPrintf(" Layer1 is %s, width %d.\n",
|
|
DBTypeLongName(RtrMetalType), RtrMetalWidth);
|
|
if (!TTMaskEqual(&RtrMetalObstacles, &DBZeroTypeBits))
|
|
{
|
|
TxPrintf(" Layer1 obstacles are:");
|
|
for (i=0; i<TT_MAXTYPES; i++)
|
|
{
|
|
if (TTMaskHasType(&RtrMetalObstacles, i))
|
|
TxPrintf(" %s(%d %d)", DBTypeLongName(i), RtrPaintSepsUp[i],
|
|
RtrPaintSepsDown[i]);
|
|
}
|
|
TxPrintf(".\n");
|
|
}
|
|
TxPrintf(" Layer2 is %s, width %d.\n",
|
|
DBTypeLongName(RtrPolyType), RtrPolyWidth);
|
|
if (!TTMaskEqual(&RtrPolyObstacles, &DBZeroTypeBits))
|
|
{
|
|
TxPrintf(" Layer2 obstacles are:");
|
|
for (i=0; i<TT_MAXTYPES; i++)
|
|
{
|
|
if (TTMaskHasType(&RtrPolyObstacles, i))
|
|
TxPrintf(" %s(%d %d)", DBTypeLongName(i), RtrPaintSepsUp[i],
|
|
RtrPaintSepsDown[i]);
|
|
}
|
|
TxPrintf(".\n");
|
|
}
|
|
TxPrintf(" Contacts are %s, width %d, offset %d.\n",
|
|
DBTypeLongName(RtrContactType), RtrContactWidth, RtrContactOffset);
|
|
TxPrintf(" Grid spacing is %d.\n", RtrGridSpacing);
|
|
TxPrintf(" Subcell separations %d up, %d down.\n",
|
|
RtrSubcellSepUp, RtrSubcellSepDown);
|
|
#endif /* notdef */
|
|
}
|
|
|
|
/*
|
|
*----------------------------------------------------------------------------
|
|
* RtrTechScale --
|
|
*
|
|
* Scale the router technology parameters as required when magic's
|
|
* internal grid is redefined relative to the technology lambda.
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
RtrTechScale(scaled, scalen)
|
|
int scaled, scalen;
|
|
{
|
|
int i;
|
|
|
|
RtrMetalWidth *= scalen;
|
|
RtrPolyWidth *= scalen;
|
|
RtrContactWidth *= scalen;
|
|
RtrContactOffset *= scalen;
|
|
RtrMetalSurround *= scalen;
|
|
RtrPolySurround *= scalen;
|
|
RtrGridSpacing *= scalen;
|
|
RtrSubcellSepUp *= scalen;
|
|
RtrSubcellSepDown *= scalen;
|
|
|
|
RtrMetalWidth /= scaled;
|
|
RtrPolyWidth /= scaled;
|
|
RtrContactWidth /= scaled;
|
|
RtrContactOffset /= scaled;
|
|
RtrMetalSurround /= scaled;
|
|
RtrPolySurround /= scaled;
|
|
RtrGridSpacing /= scaled;
|
|
RtrSubcellSepUp /= scaled;
|
|
RtrSubcellSepDown /= scaled;
|
|
|
|
for (i = 0; i < TT_MAXTYPES; i++)
|
|
{
|
|
RtrPaintSepsUp[i] *= scalen;
|
|
RtrPaintSepsDown[i] *= scalen;
|
|
RtrMetalSeps[i] *= scalen;
|
|
RtrPolySeps[i] *= scalen;
|
|
|
|
RtrPaintSepsUp[i] /= scaled;
|
|
RtrPaintSepsDown[i] /= scaled;
|
|
RtrMetalSeps[i] /= scaled;
|
|
RtrPolySeps[i] /= scaled;
|
|
}
|
|
return 0;
|
|
}
|
|
|