home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 1
/
HamRadio.cdr
/
tech
/
pcbsrcs2
/
route4.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-10
|
22KB
|
400 lines
/*
** printed circuit board autorouter, Copyright (C) Randy Nevin 1989, 1990.
**
** you may give this software to anyone, make as many copies as you like, and
** post it on public computer bulletin boards and file servers. you may not
** sell it or charge any fee for distribution (except for media and postage),
** remove this comment or the copyright notice from the code, or claim that
** you wrote this code or anything derived from it. you may modify the code as
** much as you want (please document clearly with comments, and maintain the
** coding style), but programs which are derived from this one are subject to
** the conditions stated here. i am providing this code so that people can
** learn from it, so if you distribute it, please include source code, not
** just executables. contact me to report bugs or suggest enhancements; i do
** not guarantee support, but i will make an effort to help you, and i want to
** act as a central clearing house for future versions. you should contact me
** before undertaking a significant development effort, to avoid reinventing
** the wheel. if you come up with an enhancement you consider particularly
** useful, i would appreciate being informed so that it can be incorporated in
** future versions. my address is: Randy Nevin, 1731 211th PL NE, Redmond,
** WA 98053, USA. this code is available directly from the author; just send a
** 360k floppy and a self-addressed floppy mailer with sufficient postage.
**
** HISTORY
** (name date description)
** ----------------------------------------------------
** randy nevin 2/1/89 initial version
** randy nevin 2/4/89 made retrace table driven, instead of
** doubly-nested switch statements.
** randy nevin 2/4/89 changed dir from int to char (cut
** storage for it in half).
** randy nevin 2/8/89 changed SetQueue and ReSetQueue to
** give priority to goal nodes.
** randy nevin 2/11/89 don't output incremental search
** results if stdout is redirected.
** randy nevin 2/11/89 released version 1.00
** randy nevin 5/7/89 added /N switch (don't sort
** non-PRIORITY CONNECTs)
** randy nevin 12/27/89 removed code for compensating from
** edge of hole to center of hole; just
** approximate distance between centers
** of two holes (simplify)
** randy nevin 12/29/89 added code to keep traces from
** touching corner of a hole/via cell,
** and to keep from drilling a via where
** a corner of its cell touches a trace
** randy nevin 12/29/89 released version 1.10
*/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <time.h>
#include <string.h>
#include "cell.h"
#define VERSION 3.0
/*
** if you run out of memory while routing large boards, there are two things
** you can do: (1) go into your config.sys file and disable everything you
** don't need. getting rid of things like ansi.sys, ramdisks, disk caches, and
** other terminate and stay resident (tsr) programs can free a lot of memory.
** (2) link the router, inspect the .map file, relink with the /CPARMAXALLOC:n
** switch, where n is calculated to allow for a near heap of about 5k. read
** the linker documentation before you do this. for me, the route.map file
** says the program needs 81EFh bytes. to this i add 1400h (5k) for a near
** heap to get 95EFh bytes or 95Fh paragraphs, which is 2399 decimal.
*/
int JustBoard = 0; /* need all data structures, not just the board */
int SortConnects = 1; /* default is to sort non-PRIORITY CONNECTs */
int DoubleSided = 1; /* default is to use both sides of the board. Option
added by stephen smith */
int NoDiag = 0; /* Diaganol traces allowed. Option
added by stephen smith */
int RatsNest = 0; /* Rats Nest Only is Desired */
int Manual = 0; /* Print the manual? */
int TopSide = 0; /* default is to route the solder side */
long Percent = 98; /* quit trying at 98 percent of the board tested */
int Ntotal; /* total number of CONNECTs to make */
int PartsList = 0; /* Print a parts list to a file */
FILE *partsfile;
char man[] =
"\n\n"
"the following types of input lines are legal (spaces and tabs can separate \n"
"tokens, and case is not significant): \n"
" \n"
" 1) a blank line (ignored) \n"
" 2) ';' followed by anything (ignored) \n"
" use semicolon to insert comments. \n"
" 3) DIMENSION (row,column) \n"
" this defines the number of rows and columns on the board, and must be \n"
" given before any of the lines below. note that the user sees the board \n"
" coordinate space as being 1-based, but internally it is 0-based. \n"
" 4) HOLE (row,column) \n"
" this defines a hole location. \n"
" 5) CONNECT thing AND thing \n"
" this declares that two holes are to be electrically connected. a thing \n"
" can be (row,column), or name1.name2, where name1 is the name of a \n"
" CHIPAT-defined chip, and name2 is the name of one of its pins, or a \n"
" number, giving the pin number of the named chip. you can use \"TO\" or \n"
" \"=\" instead of \"AND\" if you want. \n"
" 6) PRIORITY CONNECT thing AND thing \n"
" same as above, except the order of connections will be preserved. the \n"
" autorouter is free to reorder the non-PRIORITY CONNECTs, and in fact \n"
" reorders them shortest first. if there are PRIORITY CONNECTs, they will \n"
" all be routed before non-PRIORITY CONNECTs. \n"
" 7) INCLUDE filename \n"
" this causes the input to be temporarily taken from the given filename. \n"
" when the given filename is completely processed (EOF encountered), \n"
" control returns to the current file. INCLUDE statements may be nested \n"
" (they may occur inside the given filename). complete and partial \n"
" pathnames can be used (C:\TTL.INC, ..\TTL.INC, \TTL.INC, FOO\TTL.INC). \n"
" 8) CHIP TYPE=type PINS=number HORIZONTAL=number VERTICAL=number \n"
" [PACKAGE=package] \n"
" this declares a chip type, which can be used to place chips on the \n"
" board (see CHIPAT, below), but does not itself place anything on the \n"
" board. TYPE gives the name that will be used in later CHIPAT \n"
" statements. PINS declares the number of pins. HORIZONTAL gives the \n"
" number of 50-mil units separating adjacent pins (along the long side of \n"
" the chip). and VERTICAL gives the number of 50-mil units separating \n"
" pins across from each other (across the skinny width of the chip). \n"
" standard values for HORIZONTAL and VERTICAL are 2 and 6, respectively. \n"
" all CHIP type names must be unique. The package string must be included \n"
" if the parts listing switch is used. \n"
" 9) number=name \n"
" this declares a pin name for the chip that is currently being defined. \n"
" this statement must follow a CHIP statement. pins not defined will have \n"
" no name, but you can still refer to them by number. each pin on a chip \n"
" can be named at most once. \n"
"10) name=number \n"
" same as above. \n"
"11) CHIPAT (row,column) NAME=name TYPE=type ORIENTATION=orientation \n"
" this defines an instance of a chip, and places the appropriate holes on \n"
" the board. (row,column) is the location of pin 1. NAME defines the name \n"
" to be used in following CONNECT statements. TYPE declares the \n"
" CHIPAT-defined type of the chip. ORIENTATION can have the values \n"
" NORMAL, UP, DOWN, and UPSIDEDOWN.All CUSTOM, INLINE and CHIP names \n"
" must be unique. \n"
" \n"
" NORMAL UP DOWN UPSIDEDOWN \n"
" \n"
" 6 5 4 +---+ +---+ 3 2 1 \n"
" +-*-*-*-+ 4 * * 3 1 * | * 6 +-*-*-*-+ \n"
" | -> | 5 * ^ * 2 2 * v * 5 | <- | \n"
" +-*-*-*-+ 6 * | * 1 3 * * 4 +-*-*-*-+ \n"
" 1 2 3 +---+ +---+ 4 5 6 \n"
" \n"
" usually the highest-numbered pin (pin N) is Vcc (power) and the pin \n"
" farthest from it (pin N/2) is GND (ground). \n"
" \n"
"The following statements were added by Stephen Smith. \n"
" \n"
"12) INLINE TYPE=type PINS=number HORIZONTAL=number [PACKAGE=package] \n"
" this declares an inline type, which can be used to place chips on the \n"
" board (see CHIPAT, above), but does not itself place anything on the \n"
" board. TYPE gives the name that will be used in later INLINAT \n"
" statements. PINS declares the number of pins. HORIZONTAL gives the \n"
" number of 50-mil units separating adjacent pins. Standard value \n"
" for HORIZONTAL is 2. All INLINE type names must be unique. The package\n"
" string must be included if the parts listing switch is used. \n"
"13) INLINEAT (row,column) NAME=name TYPE=type ORIENTATION=orientation \n"
" this defines an instance of an inline, and places the appropriate \n"
" holes on the board. (row,column) is the location of pin 1. NAME defines \n"
" the name to be used in following CONNECT statements. TYPE declares the \n"
" INLINEAT-defined type of the chip. ORIENTATION can have the values \n"
" NORMAL, UP, DOWN, and UPSIDEDOWN. All CUSTOM, INLINE and CHIP \n"
" names must be unique. \n"
" \n"
" NORMAL UP DOWN UPSIDEDOWN \n"
" \n"
" 1 2 3 + + 3 2 1 \n"
" +-*-*-*-+ * 3 1 * +-*-*-*-+ \n"
" * 2 2 * \n"
" * 1 3 * \n"
" + + \n"
" \n"
"14) CUSTOM TYPE=type PACKAGE=package \n"
" In this case package is predefined in the EXE file and can be \n"
" one of the following strings: \n"
" PLCC20, PLCC28, PLCC32, PLCC44, PLCC52, PLCC68, PLCC84, \n"
" TO5, TO18, TRIMMER_W, TRIMMERP, and TRIMMERY. \n"
" These strings and the associated arrays that go with them are defined \n"
" in the file plcc.c. The numbers in the arrays are offsets from pin \n"
" number 1 on a fifty mil grid. \n"
" \n"
"15) CUSTOMAT (row,column) NAME=name TYPE=type ORIENTATION=orientation \n"
" this defines an instance of an inline, and places the appropriate \n"
" holes on the board. (row,column) is the location of pin 1. NAME defines \n"
" the name to be used in following CONNECT statements. TYPE declares the \n"
" CUSTOMAT-defined type of the chip. ORIENTATION can have the values \n"
" NORMAL, UP, DOWN, and UPSIDEDOWN. All CUSTOM, INLINE and CHIP \n"
" names must be unique. The directions shown below are for the \n"
" PLCC chip carriers. \n"
" \n"
" NORMAL UP DOWN UPSIDEDOWN \n"
" \n"
" ***** ***** **1** ***** \n"
" ******* ******* ******* ******* \n"
" ** ** ** ** ** ** ** ** \n"
" 1* ** ** ** ** ** ** *1 \n"
" ** ** ** ** ** ** ** ** \n"
" ******* ******* ******* ******* \n"
" ***** **1** ***** ***** \n"
" \n"
" \n"
" TOxx packages: \n"
" \n"
" E C \n"
" B B B E C \n"
" C E C E B \n"
" \n"
" \n"
" TRIMMERx packages: \n"
" \n"
" 3 1 \n"
" 2 2 \n"
" 1 3 2 3 1 \n"
" 2 1 3 \n"
" \n"
" Note: The coordinate system is left handed. ( Positive X values \n"
" are vertical and positive Y values are to the right. Cell (1,1) \n"
" denotes the lower left hand corner of the board. ) \n"
" \n"
" \n"
" X \n"
" ^ \n"
" | \n"
" | \n"
" +----> Y \n\n"
;
extern int Initialize( char *, int );
extern void Solve( FILE * );
extern void Report( FILE * );
void main( int, char *[] );
void main ( argc, argv ) /* input board, route traces, output routed board */
int argc;
char **argv;
{
char *self, *p;
FILE *fp, *fp2;
long start, stop, min, hours;
start = time( NULL );
self = (argv++)[0];
/* get rid of initial part of path */
if ((p = strrchr( self, '\\' )) || (p = strrchr( self, ':' )))
self = ++p;
/* get rid of extension */
if ((p = strrchr( self, '.' )) && !stricmp( p, ".EXE" ))
*p = 0;
printf( "%s.EXE, Copyright (C) Randy Nevin, 1989, 1990. Version 1.10\n"
"Modifications by Stephen Smith - Version %.2f\n\n",
self, VERSION );
printf( "See source code for rights granted.\n\n" );
while( argc-- > 1 && ( **argv == '-' || **argv == '/') )
{
++*argv;
while( **argv != '\0' )
{
switch( **argv )
{
case 'n' :
case 'N' :
++*argv;
SortConnects = 0;
break;
case 's' :
case 'S' :
++*argv;
DoubleSided = 0;
break;
case 't' :
case 'T' :
++*argv;
TopSide = 1;
break;
case 'd' :
case 'D' :
++*argv;
NoDiag = 1;
break;
case 'b' :
case 'B' :
++*argv;
TopSide = 0;
break;
case 'm' :
case 'M' :
++*argv;
Manual = 1;
break;
case '0' :
++*argv;
RatsNest = 1;
break;
case 'p' :
case 'P' :
if ( sscanf(++(*argv),"%d",&Percent ) == 0 )
{
printf("\nOption \"P\" needs a number!");
exit(1);
}
while ( **argv != NULL ) ++*argv;
break;
case 'l' :
case 'L' :
++*argv;
if ( (partsfile = fopen(*argv,"wt")) == NULL )
{
fprintf(stderr, "Couldn\'t open parts list "
"file: %s\n Program aborted\n", *argv );
exit(1);
}
while ( **argv != NULL ) ++*argv;
PartsList = 1;
break;
default :
fprintf(stderr," Unrecongized command-line switch\n"
" The valid switches are: /N, /S, /T, /B /0"
" /D /M /P /L"
"\n Program aborted\n" );
exit( 1 );
}
}
argv++;
}
if (Manual){
printf( "%s", man );
}
if ((argc < 2) || Manual) { /* need infile and outfile */
fprintf( ( (Manual) ? stdout: stderr), "usage: %s [options] infile "
"outfile [no_connect_file]\n", self );
fprintf( ( (Manual) ? stdout: stderr),
" /N = no sorting of non-PRIORITY CONNECTs\n"
" /M = Print to stdout the manual of valid input statements\n"
" /0 = Output a ratsnest ony. \n"
" /Pxxx = Percentage at which to quit trying to route \n"
" the trace. \n"
" /S = single sided printed circuit boards \n"
" /D = Diagnal Traces not allowed\n"
" /Lfile = Print out a parts listing to \"file\"\n"
" /T = Route the top side of the board. Only valid if\n "
" S is used. \n"
" /B = Route the bottom side of the board. Only valid if\n "
" S is used. Default Option. \n"
);
exit( -1 );
}
fp2 = NULL;
if (!(fp = fopen( argv[1], "wb" ))) {
fprintf( stderr, "can't open %s\n", argv[1] );
exit( -1 );
}
if ( argc > 2 ){
if (!(fp2 = fopen( argv[2], "wt" ))) {
fprintf( stderr, "can't open %s\n", argv[2] );
exit( -1 );
}
}
Ntotal = Initialize( argv[0], 1 ); /* echo memory used */
Solve( fp2 );
Report( fp );
stop = time( NULL ) - start;
min = stop / 60; stop -= min * 60;
printf( "time = %ld min%s, %ld second%s\n", min, (min == 1) ? "" : "s",
stop, (stop == 1) ? "" : "s" );
if (argc > 2 ) fclose( fp2 );
if ( PartsList ) fclose( partsfile );
exit( 0 );
}