magic/router/rtrTech.c

446 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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;
}