mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-09-02 11:08:30 +02:00
Added a ARG_UNUSED macro in utils/magic.h, which produces a simple cast to void to silence the warnings. The reasons this is used as opposed to an attribute is that most compilers should support this. Besides this, the macro can be easily searched for in the future to potentially remove (where possible) the unused parameters.
447 lines
12 KiB
C
447 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. */
|
|
{
|
|
ARG_UNUSED(sectionName);
|
|
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;
|
|
}
|
|
|