2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* tech.c --
|
|
|
|
|
*
|
|
|
|
|
* Read in a technology file.
|
|
|
|
|
*
|
2020-05-23 23:13:14 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
* * 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. *
|
2017-04-25 14:41:48 +02:00
|
|
|
* *********************************************************************
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
|
static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/utils/tech.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
|
|
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/*
|
|
|
|
|
* C99 compat
|
|
|
|
|
* Mind: tcltk/tclmagic.h must be included prior to all the other headers
|
|
|
|
|
*/
|
|
|
|
|
#include "tcltk/tclmagic.h"
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
#include "database/database.h"
|
|
|
|
|
#include "utils/magic.h"
|
|
|
|
|
#include "utils/geometry.h"
|
|
|
|
|
#include "utils/utils.h"
|
|
|
|
|
#include "utils/tech.h"
|
|
|
|
|
#include "textio/textio.h"
|
|
|
|
|
#include "windows/windows.h"
|
|
|
|
|
#include "utils/malloc.h"
|
|
|
|
|
|
2022-10-10 11:50:15 +02:00
|
|
|
/* C99 compat */
|
|
|
|
|
#include "utils/heap.h"
|
|
|
|
|
#include "cif/cif.h"
|
|
|
|
|
#include "cif/cif.h"
|
2023-01-13 23:21:37 +01:00
|
|
|
#include "cif/CIFint.h"
|
2022-10-10 11:50:15 +02:00
|
|
|
#include "drc/drc.h"
|
|
|
|
|
#include "mzrouter/mzrouter.h"
|
|
|
|
|
#include "wiring/wiring.h"
|
|
|
|
|
#include "lef/lef.h"
|
|
|
|
|
#include "router/router.h"
|
|
|
|
|
#include "irouter/irouter.h"
|
|
|
|
|
#include "garouter/garouter.h"
|
|
|
|
|
#include "extract/extract.h"
|
|
|
|
|
#include "plow/plow.h"
|
|
|
|
|
|
|
|
|
|
/* Cannot include tcltk/tclmagic.h for a clash with utils/magic.h
|
2025-01-31 18:09:05 +01:00
|
|
|
extern int Tcl_printf(FILE *, const char *, va_list); */
|
2022-10-10 11:50:15 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
global int TechFormatVersion;
|
|
|
|
|
global bool TechOverridesDefault;
|
|
|
|
|
|
|
|
|
|
/* Define a file stack so that "include" calls can be nested */
|
|
|
|
|
|
|
|
|
|
typedef struct FStack /* Linked FILE * pointers */
|
|
|
|
|
{
|
|
|
|
|
FILE *file;
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
char *filename; /* Keep file name of parent file */
|
|
|
|
|
int linenum; /* Keep line number count at the include line */
|
|
|
|
|
struct FStack *next; /* Pointer to another linked rectangle */
|
2017-04-25 14:41:48 +02:00
|
|
|
} filestack;
|
|
|
|
|
|
|
|
|
|
int techLineNumber;
|
|
|
|
|
char *TechFileName = NULL;
|
|
|
|
|
|
|
|
|
|
#define iseol(c) ((c) == EOF || (c) == '\n')
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Each client of the technology module must make itself known by
|
|
|
|
|
* a call to TechAddClient(). These calls provide both the names
|
|
|
|
|
* of the sections of the technology file, as well as the procedures
|
|
|
|
|
* to be invoked with lines in these sections.
|
|
|
|
|
*
|
|
|
|
|
* The following table is used to record clients of the technology
|
|
|
|
|
* module.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
typedef struct tC
|
|
|
|
|
{
|
|
|
|
|
bool (*tc_proc)(); /* Procedure to be called for each
|
|
|
|
|
* line in section.
|
|
|
|
|
*/
|
|
|
|
|
void (*tc_init)(); /* Procedure to be called before any
|
|
|
|
|
* lines in a section are processed.
|
|
|
|
|
*/
|
|
|
|
|
void (*tc_final)(); /* Procedure to be called after all
|
|
|
|
|
* lines in section have been processed.
|
|
|
|
|
*/
|
|
|
|
|
struct tC *tc_next; /* Next client in section */
|
|
|
|
|
} techClient;
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
char *ts_name; /* Name of section */
|
|
|
|
|
char *ts_alias; /* Alternative name of section */
|
|
|
|
|
techClient *ts_clients; /* Pointer to list of clients */
|
|
|
|
|
bool ts_read; /* Flag: TRUE if section was read */
|
|
|
|
|
bool ts_optional; /* Flag: TRUE if section is optional */
|
|
|
|
|
SectionID ts_thisSect; /* SectionID of this section */
|
|
|
|
|
SectionID ts_prevSects; /* Mask of sections that must be
|
|
|
|
|
* read in before this one. The
|
|
|
|
|
* mask is constructed from the
|
|
|
|
|
* section identifiers set by
|
|
|
|
|
* TechAddClient().
|
|
|
|
|
*/
|
|
|
|
|
} techSection;
|
|
|
|
|
|
|
|
|
|
#define MAXSECTIONS (8 * sizeof (int)) /* Not easily changeable */
|
|
|
|
|
#define MAXARGS 30
|
|
|
|
|
#define MAXLINESIZE 1024
|
|
|
|
|
|
|
|
|
|
#define SectionToMaskBit(s) (1 << (s))
|
|
|
|
|
#define SectionMaskHasSection(m, s) (m & SectionToMaskBit(s))
|
|
|
|
|
|
|
|
|
|
int techSectionNum; /* ID of next new section */
|
|
|
|
|
SectionID techSectionMask; /* Mask of sections already read */
|
|
|
|
|
|
|
|
|
|
techSection techSectionTable[MAXSECTIONS];
|
|
|
|
|
techSection *techSectionFree; /* Pointer to next free section */
|
|
|
|
|
techSection *techCurrentSection; /* Pointer to current section */
|
|
|
|
|
|
|
|
|
|
techSection *techFindSection();
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* TechSectionGetMask --
|
|
|
|
|
*
|
|
|
|
|
* Get the SectionID mask for a specific section (specified by name). The
|
|
|
|
|
* returned mask is inverted; that is, it is a mask containing bits
|
|
|
|
|
* representing all the client sections except for the one sepcified.
|
|
|
|
|
* This return value can be passed to TechLoad to re-read a specific
|
|
|
|
|
* section.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns the inverted mask for the selected section ID.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* If "depend" is non-NULL, the SectionID to which it points will be
|
|
|
|
|
* set to a mask representing the mask of sections which depend on
|
|
|
|
|
* the indicated section; that is, those sections which will be
|
|
|
|
|
* invalidated if the indicated section is altered in any way.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
SectionID
|
|
|
|
|
TechSectionGetMask(sectionName, depend)
|
|
|
|
|
char *sectionName;
|
|
|
|
|
SectionID *depend;
|
|
|
|
|
{
|
|
|
|
|
techSection *tsp, *thissect;
|
|
|
|
|
SectionID invid = 0;
|
|
|
|
|
SectionID selected;
|
|
|
|
|
|
|
|
|
|
thissect = techFindSection(sectionName);
|
|
|
|
|
if (thissect == NULL) return -1;
|
|
|
|
|
|
|
|
|
|
selected = thissect->ts_thisSect;
|
|
|
|
|
|
|
|
|
|
for (tsp = techSectionTable; tsp < techSectionFree; tsp++)
|
|
|
|
|
{
|
|
|
|
|
if (tsp != thissect)
|
|
|
|
|
{
|
|
|
|
|
invid |= tsp->ts_thisSect;
|
|
|
|
|
if (tsp->ts_prevSects & thissect->ts_thisSect)
|
2021-06-19 16:30:47 +02:00
|
|
|
if (depend != NULL) *depend = tsp->ts_thisSect;
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return invid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* TechInit --
|
|
|
|
|
*
|
|
|
|
|
* Initialize the technology module.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Initializes the technology read-in module.
|
|
|
|
|
* This function must be called before any other functions in
|
|
|
|
|
* this module are called. It is called exactly once at the start
|
|
|
|
|
* of a magic session.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
TechInit()
|
|
|
|
|
{
|
|
|
|
|
techCurrentSection = (techSection *) NULL;
|
|
|
|
|
techSectionFree = techSectionTable;
|
|
|
|
|
techSectionNum = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* TechAddAlias --
|
|
|
|
|
*
|
|
|
|
|
* Add an alternative name (alias) for a technology file section which
|
|
|
|
|
* may be used in place of the primary name.
|
|
|
|
|
*
|
|
|
|
|
* This has been added mainly to handle sections which have been
|
|
|
|
|
* expanded beyond their original definition such that the section
|
|
|
|
|
* name is no longer appropriate. Case in point: the "images"
|
|
|
|
|
* section is broader in scope than the "contact" section, but
|
|
|
|
|
* because contacts are a subset of images in version 7.3, it is
|
|
|
|
|
* preferable to have an "images" section instead of a "contacts"
|
|
|
|
|
* section, with allowances for backwards compatibility.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Allocates string memory.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
TechAddAlias(primaryName, alias)
|
|
|
|
|
char *primaryName;
|
|
|
|
|
char *alias;
|
|
|
|
|
{
|
|
|
|
|
techSection *tsp;
|
|
|
|
|
|
|
|
|
|
tsp = techFindSection(primaryName);
|
|
|
|
|
if (tsp == (techSection *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Unknown technology file section \"%s\" requested.\n",
|
|
|
|
|
primaryName);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (tsp->ts_alias != NULL)
|
|
|
|
|
freeMagic(tsp->ts_alias);
|
|
|
|
|
tsp->ts_alias = StrDup((char **)NULL, alias);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* changePlanesFunc() ---
|
|
|
|
|
*
|
|
|
|
|
* This function hacks the existing layout database in case a tech file
|
|
|
|
|
* is loaded which contains more or fewer planes than the exisiting
|
|
|
|
|
* technology. This is doing nothing fancy; it is simply making sure
|
|
|
|
|
* that all memory allocation is accounted for.
|
|
|
|
|
*
|
|
|
|
|
* As a note for future implementation, it would be helpful to keep the
|
|
|
|
|
* old plane name definitions around and try to match up the old and new
|
|
|
|
|
* planes, so that it is possible to load a technology file which matches
|
|
|
|
|
* the existing technology except for the addition or subtraction of one
|
|
|
|
|
* or more planes (e.g., extra metal layer option) without completely
|
|
|
|
|
* invalidating an existing layout.
|
|
|
|
|
*
|
|
|
|
|
* As written, this function is inherently dangerous. It is intended for
|
|
|
|
|
* use when loading a new tech file when there is no layout, just empty
|
|
|
|
|
* tile planes.
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
changePlanesFunc(cellDef, arg)
|
|
|
|
|
CellDef *cellDef;
|
|
|
|
|
int *arg;
|
|
|
|
|
{
|
|
|
|
|
int oldnumplanes = *arg;
|
|
|
|
|
int pNum;
|
|
|
|
|
|
|
|
|
|
if (oldnumplanes < DBNumPlanes)
|
|
|
|
|
{
|
|
|
|
|
/* New planes to be added */
|
|
|
|
|
for (pNum = oldnumplanes; pNum < DBNumPlanes; pNum++)
|
|
|
|
|
{
|
|
|
|
|
cellDef->cd_planes[pNum] = DBNewPlane((ClientData) TT_SPACE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Old planes to be subtracted */
|
|
|
|
|
for (pNum = DBNumPlanes; pNum < oldnumplanes; pNum++)
|
|
|
|
|
{
|
2020-12-16 17:49:24 +01:00
|
|
|
if (cellDef->cd_planes[pNum] != NULL)
|
|
|
|
|
{
|
|
|
|
|
DBFreePaintPlane(cellDef->cd_planes[pNum]);
|
|
|
|
|
TiFreePlane(cellDef->cd_planes[pNum]);
|
|
|
|
|
cellDef->cd_planes[pNum] = (Plane *) NULL;
|
|
|
|
|
}
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* TechAddClient --
|
|
|
|
|
*
|
|
|
|
|
* Add a client to the technology module.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Identifies "sectionName" as a valid name for a section of a .tech
|
|
|
|
|
* file, and specifies that init() is the procedure to be called when
|
|
|
|
|
* a new technology is loaded, proc() as the procedure to be called
|
|
|
|
|
* for each line in the given section, and final() as the procedure to
|
|
|
|
|
* be called after the last line in the given section.
|
|
|
|
|
*
|
|
|
|
|
* The init() procedure takes no arguments.
|
|
|
|
|
* The proc() procedure should be of the following form:
|
|
|
|
|
* bool
|
|
|
|
|
* proc(sectionName, argc, argv)
|
|
|
|
|
* char *sectionName;
|
|
|
|
|
* int argc;
|
|
|
|
|
* char *argv[];
|
|
|
|
|
* {
|
|
|
|
|
* }
|
|
|
|
|
* The final() procedure takes no arguments.
|
|
|
|
|
*
|
|
|
|
|
* The argument prevSections should be a mask of the SectionID's
|
|
|
|
|
* of all sections that must be read in before this one.
|
|
|
|
|
*
|
|
|
|
|
* If the argument 'pSectionID' is non-NULL, it should point to
|
|
|
|
|
* an int that will be set to the sectionID of this section.
|
|
|
|
|
*
|
|
|
|
|
* It is legal for several procedures to be associated with a given
|
|
|
|
|
* sectionName; this is accomplished through successive calls to
|
|
|
|
|
* TechAddClient with the same sectionName. The procedures will
|
|
|
|
|
* be invoked in the order in which they were handed to TechAddClient().
|
|
|
|
|
*
|
|
|
|
|
* If the procedure given is NULL for init(), proc(), or final(), no
|
|
|
|
|
* procedure is invoked.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
TechAddClient(sectionName, init, proc, final, prevSections, pSectionID, opt)
|
|
|
|
|
char *sectionName;
|
|
|
|
|
void (*init)();
|
|
|
|
|
bool (*proc)();
|
|
|
|
|
void (*final)();
|
|
|
|
|
SectionID prevSections;
|
|
|
|
|
SectionID *pSectionID;
|
|
|
|
|
bool opt; /* optional section */
|
|
|
|
|
{
|
|
|
|
|
techSection *tsp;
|
|
|
|
|
techClient *tcp, *tcl;
|
|
|
|
|
|
|
|
|
|
tsp = techFindSection(sectionName);
|
|
|
|
|
if (tsp == (techSection *) NULL)
|
|
|
|
|
{
|
|
|
|
|
tsp = techSectionFree++;
|
|
|
|
|
ASSERT(tsp < &techSectionTable[MAXSECTIONS], "TechAddClient");
|
|
|
|
|
tsp->ts_name = StrDup((char **) NULL, sectionName);
|
|
|
|
|
tsp->ts_alias = NULL;
|
|
|
|
|
tsp->ts_clients = (techClient *) NULL;
|
|
|
|
|
tsp->ts_thisSect = SectionToMaskBit(techSectionNum);
|
|
|
|
|
tsp->ts_prevSects = (SectionID) 0;
|
|
|
|
|
tsp->ts_optional = opt;
|
|
|
|
|
techSectionNum++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tsp->ts_prevSects |= prevSections;
|
|
|
|
|
if (pSectionID)
|
|
|
|
|
*pSectionID = tsp->ts_thisSect;
|
|
|
|
|
|
|
|
|
|
tcp = (techClient *) mallocMagic(sizeof (techClient));
|
|
|
|
|
ASSERT(tcp != (techClient *) NULL, "TechAddClient");
|
|
|
|
|
tcp->tc_init = init;
|
|
|
|
|
tcp->tc_proc = proc;
|
|
|
|
|
tcp->tc_final = final;
|
|
|
|
|
tcp->tc_next = (techClient *) NULL;
|
|
|
|
|
|
|
|
|
|
if (tsp->ts_clients == (techClient *) NULL)
|
|
|
|
|
tsp->ts_clients = tcp;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (tcl = tsp->ts_clients; tcl->tc_next; tcl = tcl->tc_next)
|
|
|
|
|
/* Nothing */;
|
|
|
|
|
tcl->tc_next = tcp;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
* TechLoad --
|
|
|
|
|
*
|
|
|
|
|
* Initialize technology description information from a file.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* TRUE if technology is successfully initialized (all required
|
|
|
|
|
* sections present and error free); FALSE otherwise. Unrecognized
|
|
|
|
|
* sections cause an error message to be printed, but do not otherwise
|
|
|
|
|
* affect the result returned by TechLoad().
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Calls technology initialization routines of other modules
|
|
|
|
|
* to initialize technology-specific information.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
TechLoad(filename, initmask)
|
|
|
|
|
char *filename;
|
|
|
|
|
SectionID initmask;
|
|
|
|
|
{
|
|
|
|
|
FILE *tf;
|
|
|
|
|
techSection *tsp;
|
|
|
|
|
techClient *tcp;
|
|
|
|
|
char suffix[20], line[MAXLINESIZE], *realname;
|
|
|
|
|
char *argv[MAXARGS];
|
|
|
|
|
SectionID mask, badMask;
|
|
|
|
|
int argc, s;
|
|
|
|
|
bool retval, skip;
|
|
|
|
|
filestack *fstack, *newstack;
|
|
|
|
|
filestack topfile;
|
|
|
|
|
|
|
|
|
|
fstack = NULL;
|
|
|
|
|
techLineNumber = 0;
|
|
|
|
|
badMask = (SectionID) 0;
|
|
|
|
|
int saveNumPlanes;
|
|
|
|
|
|
|
|
|
|
int changePlanesFunc(); /* forward declaration */
|
|
|
|
|
int checkForPaintFunc(); /* forward declaration */
|
|
|
|
|
|
|
|
|
|
if (initmask == -1)
|
|
|
|
|
{
|
|
|
|
|
TxError("Invalid technology file section requested.\n");
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-11 16:51:14 +02:00
|
|
|
/* TECH_VERSION in the filename is deprecated as of magic version */
|
|
|
|
|
/* 7.2.27; TECH_VERSION is no longer defined in the utils/Makefile.*/
|
|
|
|
|
/* It has been changed to TECH_FORMAT_VERSION, left at version 27, */
|
|
|
|
|
/* and placed in utils/tech.h. It is needed for backward */
|
|
|
|
|
/* compatibility with the old *.tech27 file format. */
|
|
|
|
|
|
|
|
|
|
(void) sprintf(suffix, ".tech");
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* If NULL is passed to argument "filename", this is a reload and */
|
|
|
|
|
/* we should read TechFileName verbatim. */
|
|
|
|
|
|
2021-11-24 16:56:08 +01:00
|
|
|
if (filename == NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2021-11-24 16:56:08 +01:00
|
|
|
if (TechFileName != NULL)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
2021-11-24 16:56:08 +01:00
|
|
|
tf = PaOpen(TechFileName, "r", (char *)NULL, ".", SysLibPath, &realname);
|
|
|
|
|
if (tf == (FILE *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Could not find file '%s' in any of these "
|
2017-04-25 14:41:48 +02:00
|
|
|
"directories:\n %s\n",
|
|
|
|
|
TechFileName, SysLibPath);
|
2021-11-24 16:56:08 +01:00
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
TxError("Invalid technology file load.\n");
|
2017-04-25 14:41:48 +02:00
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *sptr, *dptr;
|
|
|
|
|
|
2022-01-01 19:24:18 +01:00
|
|
|
tf = (FILE *)NULL;
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Added 1/20/2015 to correspond to change to PaLockOpen(); */
|
|
|
|
|
/* Always strip suffix from filename when suffix is specified. */
|
|
|
|
|
|
|
|
|
|
sptr = strrchr(filename, '/');
|
|
|
|
|
if (sptr == NULL)
|
|
|
|
|
sptr = filename;
|
|
|
|
|
else
|
|
|
|
|
sptr++;
|
|
|
|
|
|
2021-11-24 16:56:08 +01:00
|
|
|
/* If the filename is ".tech", then remove the extension and */
|
|
|
|
|
/* process like it was not there at all. */
|
2017-04-25 14:41:48 +02:00
|
|
|
dptr = strrchr(sptr, '.');
|
2021-11-24 16:56:08 +01:00
|
|
|
if ((dptr != NULL) && !strcmp(dptr, suffix))
|
2017-04-25 14:41:48 +02:00
|
|
|
*dptr = '\0';
|
|
|
|
|
|
2021-11-24 16:56:08 +01:00
|
|
|
/* If a non-standard extension was used, then honor it */
|
|
|
|
|
if ((dptr != NULL) && (*dptr != '\0'))
|
2022-01-01 19:24:18 +01:00
|
|
|
{
|
2021-11-24 16:56:08 +01:00
|
|
|
tf = PaOpen(filename, "r", (char *)NULL, ".", SysLibPath, &realname);
|
2022-01-01 19:24:18 +01:00
|
|
|
|
|
|
|
|
/* If that didn't work, fall back to trying the filename */
|
|
|
|
|
/* with the suffix. This is needed for some ill-considered */
|
|
|
|
|
/* names like "SCN4M_SUBM.20.tech". */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tf == (FILE *)NULL)
|
2021-11-24 16:56:08 +01:00
|
|
|
tf = PaOpen(filename, "r", suffix, ".", SysLibPath, &realname);
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
if (tf == (FILE *) NULL)
|
|
|
|
|
{
|
|
|
|
|
/* Try looking for tech files from the last version to */
|
|
|
|
|
/* put the version number into the filename itself. */
|
|
|
|
|
|
|
|
|
|
(void) sprintf(suffix, ".tech%d", TECH_FORMAT_VERSION);
|
|
|
|
|
|
|
|
|
|
tf = PaOpen(filename, "r", suffix, ".", SysLibPath, &realname);
|
|
|
|
|
if (tf == (FILE *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TxError("Could not find file '%s.tech' in any of these "
|
|
|
|
|
"directories:\n %s\n",
|
|
|
|
|
filename, SysLibPath);
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
StrDup(&TechFileName, realname);
|
|
|
|
|
|
|
|
|
|
// In case filename is not a temporary string, put it back the
|
|
|
|
|
// way it was.
|
|
|
|
|
if (dptr != NULL) *dptr = '.';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
topfile.file = tf;
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
topfile.filename = NULL;
|
|
|
|
|
topfile.linenum = 0;
|
2017-04-25 14:41:48 +02:00
|
|
|
topfile.next = NULL;
|
|
|
|
|
fstack = &topfile;
|
|
|
|
|
|
|
|
|
|
// If TechLoad is called with initmask == -2, test that the file
|
|
|
|
|
// exists and is readable, and that the first non-comment line
|
|
|
|
|
// is the keyword "tech".
|
|
|
|
|
|
|
|
|
|
if (initmask == -2)
|
|
|
|
|
{
|
|
|
|
|
argc = techGetTokens(line, sizeof line, &fstack, argv);
|
|
|
|
|
fclose(tf);
|
|
|
|
|
if (argc != 1) return (FALSE);
|
|
|
|
|
if (strcmp(argv[0], "tech")) return (FALSE);
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Mark all sections as being unread.
|
|
|
|
|
*/
|
|
|
|
|
techSectionMask = initmask;
|
|
|
|
|
for (tsp = techSectionTable; tsp < techSectionFree; tsp++)
|
|
|
|
|
{
|
|
|
|
|
tsp->ts_read = FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Run section initializations if this is not a reload.
|
|
|
|
|
* CIF istyle, CIF ostyle, and extract sections need calls
|
|
|
|
|
* to the init functions which clean up memory devoted to
|
|
|
|
|
* remembering all the styles.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (filename != NULL)
|
|
|
|
|
{
|
|
|
|
|
#ifdef CIF_MODULE
|
|
|
|
|
CIFTechInit();
|
|
|
|
|
CIFReadTechInit();
|
|
|
|
|
#endif
|
|
|
|
|
ExtTechInit();
|
|
|
|
|
DRCTechInit();
|
2024-10-02 07:59:00 +02:00
|
|
|
#ifdef ROUTE_MODULE
|
2020-05-23 23:13:14 +02:00
|
|
|
MZTechInit();
|
2024-10-02 07:59:00 +02:00
|
|
|
#endif
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Changing number of planes requires handling on every */
|
|
|
|
|
/* celldef. So we need to save the original number of */
|
|
|
|
|
/* planes to see if it shrinks or expands. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
saveNumPlanes = DBNumPlanes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Sections in a technology file begin with a single line containing
|
|
|
|
|
* the keyword identifying the section, and end with a single line
|
|
|
|
|
* containing the keyword "end".
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
retval = TRUE;
|
|
|
|
|
skip = FALSE;
|
|
|
|
|
while ((argc = techGetTokens(line, sizeof line, &fstack, argv)) >= 0)
|
|
|
|
|
{
|
|
|
|
|
/* Check for file inclusions (can be nested) */
|
|
|
|
|
if ((argc > 1) && (!strcmp(argv[0], "include")))
|
|
|
|
|
{
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
char *sptr, *increalname;
|
2017-04-25 14:41:48 +02:00
|
|
|
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
tf = PaOpen(argv[1], "r", suffix, ".", SysLibPath, &increalname);
|
2017-04-25 14:41:48 +02:00
|
|
|
if (tf != NULL)
|
|
|
|
|
{
|
|
|
|
|
newstack = (filestack *)mallocMagic(sizeof(filestack));
|
|
|
|
|
newstack->file = tf;
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
newstack->filename = TechFileName;
|
|
|
|
|
newstack->linenum = techLineNumber;
|
2017-04-25 14:41:48 +02:00
|
|
|
newstack->next = fstack;
|
|
|
|
|
fstack = newstack;
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
techLineNumber = 0;
|
|
|
|
|
TechFileName = StrDup((char **)NULL, increalname);
|
2017-04-25 14:41:48 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check the directory from which the tech file */
|
|
|
|
|
/* itself was read. */
|
|
|
|
|
|
|
|
|
|
if ((sptr = strrchr(TechFileName, '/')) != NULL)
|
|
|
|
|
{
|
|
|
|
|
*sptr = '\0';
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
tf = PaOpen(argv[1], "r", suffix, TechFileName, NULL, &increalname);
|
2017-04-25 14:41:48 +02:00
|
|
|
*sptr = '/';
|
|
|
|
|
if (tf != NULL)
|
|
|
|
|
{
|
|
|
|
|
newstack = (filestack *)mallocMagic(sizeof(filestack));
|
|
|
|
|
newstack->file = tf;
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
newstack->filename = TechFileName;
|
|
|
|
|
newstack->linenum = techLineNumber;
|
2017-04-25 14:41:48 +02:00
|
|
|
newstack->next = fstack;
|
|
|
|
|
fstack = newstack;
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
techLineNumber = 0;
|
|
|
|
|
TechFileName = StrDup((char **)NULL, increalname);
|
2017-04-25 14:41:48 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TechError("Warning: Couldn't find include file %s\n", argv[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!skip && techCurrentSection == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (argc != 1)
|
|
|
|
|
{
|
|
|
|
|
TechError("Bad section header line\n");
|
|
|
|
|
goto skipsection;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tsp = techFindSection(argv[0]);
|
|
|
|
|
if (tsp == (techSection *) NULL)
|
|
|
|
|
{
|
|
|
|
|
TechError("Unrecognized section name: %s\n", argv[0]);
|
|
|
|
|
goto skipsection;
|
|
|
|
|
}
|
|
|
|
|
else if (initmask & tsp->ts_thisSect)
|
|
|
|
|
{
|
|
|
|
|
skip = TRUE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2024-10-04 18:21:15 +02:00
|
|
|
if ((mask = (tsp->ts_prevSects & ~techSectionMask)))
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
techSection *sp;
|
|
|
|
|
|
|
|
|
|
TechError("Section %s appears too early.\n", argv[0]);
|
|
|
|
|
TxError("\tMissing prerequisite sections:\n");
|
|
|
|
|
for (sp = techSectionTable; sp < techSectionFree; sp++)
|
|
|
|
|
if (mask & sp->ts_thisSect)
|
|
|
|
|
TxError("\t\t%s\n", sp->ts_name);
|
|
|
|
|
goto skipsection;
|
|
|
|
|
}
|
|
|
|
|
techCurrentSection = tsp;
|
|
|
|
|
|
|
|
|
|
/* Invoke initialization routines for all clients that
|
|
|
|
|
* provided them.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
for (tcp = techCurrentSection->ts_clients;
|
|
|
|
|
tcp != NULL;
|
|
|
|
|
tcp = tcp->tc_next)
|
|
|
|
|
{
|
|
|
|
|
if (tcp->tc_init)
|
|
|
|
|
(void) (*tcp->tc_init)();
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* At the end of the section, invoke the finalization routine
|
|
|
|
|
* of the client's, if there is one.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (argc == 1 && strcmp(argv[0], "end") == 0)
|
|
|
|
|
{
|
|
|
|
|
if (!skip)
|
|
|
|
|
{
|
|
|
|
|
techSectionMask |= techCurrentSection->ts_thisSect;
|
|
|
|
|
techCurrentSection->ts_read = TRUE;
|
|
|
|
|
for (tcp = techCurrentSection->ts_clients;
|
|
|
|
|
tcp != NULL;
|
|
|
|
|
tcp = tcp->tc_next)
|
|
|
|
|
{
|
|
|
|
|
if (tcp->tc_final)
|
|
|
|
|
(*tcp->tc_final)();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
techCurrentSection = (techSection *) NULL;
|
|
|
|
|
skip = FALSE;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!skip)
|
|
|
|
|
for (tcp = techCurrentSection->ts_clients;
|
|
|
|
|
tcp != NULL;
|
|
|
|
|
tcp = tcp->tc_next)
|
|
|
|
|
if (tcp->tc_proc)
|
|
|
|
|
{
|
|
|
|
|
if (!(*tcp->tc_proc)(techCurrentSection->ts_name,argc,argv))
|
|
|
|
|
{
|
|
|
|
|
retval = FALSE;
|
|
|
|
|
badMask |= techCurrentSection->ts_thisSect;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
skipsection:
|
|
|
|
|
TxError("[Skipping to \"end\"]\n");
|
|
|
|
|
skip = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (badMask)
|
|
|
|
|
{
|
|
|
|
|
TxError("The following sections of %s contained errors:\n", TechFileName);
|
|
|
|
|
for (s = 0; s < techSectionNum; s++)
|
|
|
|
|
if (SectionMaskHasSection(badMask, s))
|
|
|
|
|
TxError(" %s\n", techSectionTable[s].ts_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (tsp = techSectionTable; tsp < techSectionFree; tsp++)
|
|
|
|
|
{
|
|
|
|
|
if (!(initmask & tsp->ts_thisSect))
|
|
|
|
|
{
|
|
|
|
|
if (!tsp->ts_read && !tsp->ts_optional)
|
|
|
|
|
{
|
|
|
|
|
TxError("Section \"%s\" was missing from %s.\n",
|
|
|
|
|
tsp->ts_name, TechFileName);
|
|
|
|
|
retval = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* In case we hit an error in an included file. . . */
|
|
|
|
|
while ((fstack != NULL) && (fstack != &topfile))
|
|
|
|
|
{
|
|
|
|
|
fclose(fstack->file);
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
freeMagic(fstack->filename);
|
2025-02-13 09:11:16 +01:00
|
|
|
free_magic1_t mm1 = freeMagic1_init();
|
|
|
|
|
freeMagic1(&mm1, fstack);
|
2017-04-25 14:41:48 +02:00
|
|
|
fstack = fstack->next;
|
2025-02-13 09:11:16 +01:00
|
|
|
freeMagic1_end(&mm1);
|
2017-04-25 14:41:48 +02:00
|
|
|
}
|
|
|
|
|
if (fstack) fclose(fstack->file);
|
|
|
|
|
|
|
|
|
|
/* Note: If filename is NULL, then individual sections are */
|
|
|
|
|
/* being reloaded, and it is the responsibility of the */
|
|
|
|
|
/* calling routine to invoke any exit function specific to */
|
|
|
|
|
/* that section (e.g., DRCTechScale() when loading a new */
|
|
|
|
|
/* DRC style). */
|
|
|
|
|
|
|
|
|
|
if ((filename != NULL) && (retval == TRUE))
|
|
|
|
|
{
|
2023-01-13 23:21:37 +01:00
|
|
|
/* If the tech file insists that the grid should be set */
|
|
|
|
|
/* to the minimum, then enforce it. */
|
|
|
|
|
if (CIFCurStyle && (CIFCurStyle->cs_flags & CWF_MINIMUM_GRID))
|
|
|
|
|
{
|
|
|
|
|
DBLambda[0] = 1;
|
|
|
|
|
DBLambda[1] = CIFCurStyle->cs_scaleFactor / CIFCurStyle->cs_gridLimit;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* If internal scalefactor is not the default 1:1, then we */
|
|
|
|
|
/* need to scale the techfile numbers accordingly. */
|
|
|
|
|
|
|
|
|
|
if ((DBLambda[0] != 1) || (DBLambda[1] != 1))
|
|
|
|
|
{
|
|
|
|
|
int d = DBLambda[0];
|
|
|
|
|
int n = DBLambda[1];
|
|
|
|
|
|
|
|
|
|
CIFTechInputScale(d, n, TRUE);
|
|
|
|
|
CIFTechOutputScale(d, n);
|
|
|
|
|
DRCTechScale(d, n);
|
|
|
|
|
ExtTechScale(d, n);
|
|
|
|
|
WireTechScale(d, n);
|
|
|
|
|
#ifdef LEF_MODULE
|
|
|
|
|
LefTechScale(d, n);
|
2022-11-20 21:15:04 +01:00
|
|
|
LefTechSetDefaults();
|
2017-04-25 14:41:48 +02:00
|
|
|
#endif
|
|
|
|
|
#ifdef ROUTE_MODULE
|
|
|
|
|
RtrTechScale(d, n);
|
|
|
|
|
#endif
|
|
|
|
|
TxPrintf("Scaled tech values by %d / %d to"
|
|
|
|
|
" match internal grid scaling\n", n, d);
|
|
|
|
|
|
|
|
|
|
/* Check if we're below the scale set by cifoutput gridlimit */
|
|
|
|
|
if (CIFTechLimitScale(1, 1))
|
|
|
|
|
TxError("WARNING: Current grid scale is smaller"
|
|
|
|
|
" than the minimum for the process!\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Post-technology reading routines */
|
|
|
|
|
|
|
|
|
|
#ifdef ROUTE_MODULE
|
|
|
|
|
MZAfterTech();
|
|
|
|
|
IRAfterTech();
|
|
|
|
|
GAMazeInitParms();
|
|
|
|
|
#endif
|
|
|
|
|
PlowAfterTech();
|
|
|
|
|
|
|
|
|
|
if (DBCellSrDefs(0, checkForPaintFunc, (ClientData)&saveNumPlanes))
|
|
|
|
|
{
|
|
|
|
|
if (saveNumPlanes != DBNumPlanes)
|
|
|
|
|
TxError("Warning: Number of planes has changed. ");
|
|
|
|
|
TxError("Existing layout may be invalid.\n");
|
|
|
|
|
}
|
|
|
|
|
if (saveNumPlanes != DBNumPlanes)
|
|
|
|
|
DBCellSrDefs(0, changePlanesFunc, (ClientData) &saveNumPlanes);
|
|
|
|
|
}
|
|
|
|
|
else if (retval == FALSE)
|
|
|
|
|
{
|
|
|
|
|
/* On error, remove any existing technology file name */
|
2021-11-24 16:56:08 +01:00
|
|
|
DBNumPlanes = saveNumPlanes;
|
2017-04-25 14:41:48 +02:00
|
|
|
freeMagic(TechFileName);
|
|
|
|
|
TechFileName = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (retval);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* TechError --
|
|
|
|
|
*
|
|
|
|
|
* Print an error message referring to a given line number in the
|
|
|
|
|
* technology module.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Prints an error message.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
TechPrintLine()
|
|
|
|
|
{
|
|
|
|
|
char *section;
|
|
|
|
|
|
|
|
|
|
if (techCurrentSection)
|
|
|
|
|
section = techCurrentSection->ts_name;
|
|
|
|
|
else
|
|
|
|
|
section = "(none)";
|
|
|
|
|
|
|
|
|
|
TxError("%s: line %d: section %s:\n\t",
|
|
|
|
|
TechFileName, techLineNumber, section);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2024-10-03 23:47:50 +02:00
|
|
|
TechError(const char *fmt, ...)
|
2017-04-25 14:41:48 +02:00
|
|
|
{
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
TechPrintLine();
|
|
|
|
|
va_start(args, fmt);
|
|
|
|
|
Vfprintf(stderr, fmt, args);
|
|
|
|
|
va_end(args);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* ================== Functions local to this module ================== */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* techFindSection --
|
|
|
|
|
*
|
|
|
|
|
* Return a pointer to the entry in techSectionTable for the section
|
|
|
|
|
* of the given name.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* A pointer to the new entry, or NULL if none could be found.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* None.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
techSection *
|
|
|
|
|
techFindSection(sectionName)
|
|
|
|
|
char *sectionName;
|
|
|
|
|
{
|
|
|
|
|
techSection *tsp;
|
|
|
|
|
|
|
|
|
|
for (tsp = techSectionTable; tsp < techSectionFree; tsp++)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(tsp->ts_name, sectionName))
|
|
|
|
|
return (tsp);
|
|
|
|
|
else if (tsp->ts_alias != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp(tsp->ts_alias, sectionName))
|
|
|
|
|
return (tsp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ((techSection *) NULL);
|
|
|
|
|
}
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* techGetTokens --
|
|
|
|
|
*
|
|
|
|
|
* Read a line from the technology file and split it up into tokens.
|
|
|
|
|
* Blank lines are ignored. Lines ending in backslash are joined
|
|
|
|
|
* to their successor lines.
|
|
|
|
|
* We assume that all macro definition and comment elimination has
|
|
|
|
|
* been done by the C preprocessor.
|
|
|
|
|
*
|
|
|
|
|
* Results:
|
|
|
|
|
* Returns the number of tokens into which the line was split, or
|
|
|
|
|
* -1 on end of file. Never returns 0.
|
|
|
|
|
*
|
|
|
|
|
* Side effects:
|
|
|
|
|
* Copies the line just read into 'line'. The trailing newline
|
|
|
|
|
* is turned into a '\0'. The line is broken into tokens which
|
|
|
|
|
* are then placed into argv.
|
|
|
|
|
*
|
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
techGetTokens(line, size, fstack, argv)
|
|
|
|
|
char *line; /* Character array into which line is read */
|
|
|
|
|
int size; /* Size of character array */
|
|
|
|
|
filestack **fstack; /* Open technology file on top of stack */
|
|
|
|
|
char *argv[]; /* Vector of tokens built by techGetTokens() */
|
|
|
|
|
{
|
|
|
|
|
char *get, *put, *getp;
|
|
|
|
|
bool inquote;
|
|
|
|
|
int argc = 0;
|
|
|
|
|
int currspace; /* chars remaining before end of line[size] */
|
|
|
|
|
FILE *file; /* Current technology file */
|
|
|
|
|
|
|
|
|
|
file = (*fstack)->file;
|
|
|
|
|
|
|
|
|
|
/* Read one line into the buffer, joining lines when they end
|
|
|
|
|
* in backslashes.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Code revision (MDG, Stanford): Prevent the 1024-character limit due */
|
|
|
|
|
/* to unconditional decrement of size. Long comment lists could cause */
|
|
|
|
|
/* infinite looping. New code interprets first non-space character '#' */
|
|
|
|
|
/* as a comment character, rather than requiring it to be in the first */
|
|
|
|
|
/* column. */
|
|
|
|
|
|
|
|
|
|
/* Code revision (RTE, Open Circuit Design): Handle DOS-style CR/LF */
|
|
|
|
|
/* Code revision (RTE, Open Circuit Design): Handle "include" files */
|
|
|
|
|
|
|
|
|
|
start:
|
|
|
|
|
get = line;
|
|
|
|
|
currspace = size;
|
|
|
|
|
while (currspace > 0)
|
|
|
|
|
{
|
|
|
|
|
techLineNumber += 1;
|
|
|
|
|
while (fgets(get, currspace, file) == NULL) {
|
|
|
|
|
if ((*fstack)->next != NULL)
|
|
|
|
|
{
|
|
|
|
|
fclose((*fstack)->file);
|
A number of changes:
1) Corrected spurious error messages about cells already existing
in GDS when using "flatten" or "flatglob".
2) Fixed handling of resistance as a subcircuit parameter
3) Added area and perimeter resistance for a device; this is done
through the "devresist" statement in the tech file, which is an
extension of the original "fetresist" statement. Where "fetresist"
only supported type "linear", "devresist" supports types "area"
and "perimeter".
4) Support for CDL syntax, including generating subcircuit-like
parameters for components starting with SPICE-standard prefixes
like M, R, C, etc., adding "/" between pins and subcircuit name,
and saving the file as ".cdl" instead of ".spice".
5) Estimated L and W for devices whose geometry is complex and do not
reduce to a simple rectangle. L and W are estimated as the square
root of the area.
6) Changed the method of extracting L and W for diodes to use the same
method as capacitors. Note that diodes are not usually specified
by L and W, but if they are, this will produce the right result.
7) Corrected the reported filename and line number when printing error
messages related to errors inside a technology file, when the
technology file uses "include" to combine multiple files.
2025-10-01 21:17:49 +02:00
|
|
|
freeMagic(TechFileName);
|
|
|
|
|
TechFileName = (*fstack)->filename;
|
|
|
|
|
techLineNumber = (*fstack)->linenum;
|
2017-04-25 14:41:48 +02:00
|
|
|
*fstack = (*fstack)->next;
|
|
|
|
|
file = (*fstack)->file;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return (-1);
|
|
|
|
|
}
|
|
|
|
|
getp = get;
|
|
|
|
|
while(isspace(*getp)) getp++;
|
|
|
|
|
if (*getp == '#') continue;
|
|
|
|
|
for (put = get; *put != '\n'; put++) currspace -= 1;
|
|
|
|
|
if (put != get)
|
|
|
|
|
{
|
|
|
|
|
put--;
|
|
|
|
|
if (*put == 0xd) put--; /* Handle DOS-style CR/LF */
|
|
|
|
|
if (*put == '\\')
|
|
|
|
|
{
|
|
|
|
|
get = put;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
put++;
|
|
|
|
|
}
|
|
|
|
|
*put= '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (currspace == 0) TechError("long line truncated\n");
|
|
|
|
|
|
|
|
|
|
get = put = line;
|
|
|
|
|
|
|
|
|
|
while (*get != '\0')
|
|
|
|
|
{
|
|
|
|
|
/* Skip leading blanks */
|
|
|
|
|
|
|
|
|
|
while (isspace(*get)) get++;
|
|
|
|
|
|
|
|
|
|
/* Beginning of the token is here. */
|
|
|
|
|
|
|
|
|
|
argv[argc] = put = get;
|
|
|
|
|
if (*get == '"')
|
|
|
|
|
{
|
|
|
|
|
get++;
|
|
|
|
|
inquote = TRUE;
|
|
|
|
|
} else inquote = FALSE;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Grab up characters to the end of the token. Any character
|
|
|
|
|
* preceded by a backslash is taken literally.
|
|
|
|
|
*/
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
while (*get != '\0')
|
|
|
|
|
{
|
|
|
|
|
if (inquote)
|
|
|
|
|
{
|
|
|
|
|
if (*get == '"') break;
|
|
|
|
|
}
|
|
|
|
|
else if (isspace(*get)) break;
|
|
|
|
|
|
|
|
|
|
if (*get == '\\') /* Process quoted characters literally */
|
|
|
|
|
{
|
|
|
|
|
get += 1;
|
|
|
|
|
if (*get == '\0') break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy into token receiving area */
|
|
|
|
|
*put++ = *get++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we got no characters in the token, we must have been at
|
|
|
|
|
* the end of the line.
|
|
|
|
|
*/
|
|
|
|
|
if (get == argv[argc])
|
|
|
|
|
break;
|
2020-05-23 23:13:14 +02:00
|
|
|
|
2017-04-25 14:41:48 +02:00
|
|
|
/* Terminate the token and advance over the terminating character. */
|
|
|
|
|
|
|
|
|
|
if (*get != '\0') get++; /* Careful! could be at end of line! */
|
|
|
|
|
*put++ = '\0';
|
|
|
|
|
argc++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (argc == 0)
|
|
|
|
|
goto start;
|
|
|
|
|
|
|
|
|
|
return (argc);
|
|
|
|
|
}
|