// AddIO2BDnet.c // // Revision 0, 2006-11-11: Version 0.01 by Steve Beccue // Revision 1, 2008-09-09: Version 0.03 by Tim Edwards // Revision 2, 2009-07-13: Version 0.04 cleanups by Philipp Klaus Krause. // #include #include #include #include #include #include #define EXIT_SUCCESS 0 #define EXIT_FAILURE 1 #define EXIT_HELP 2 #define TRUE 1 #define FALSE 0 #define NMOS 1 #define PMOS 0 #define LengthOfNodeName 100 #define LengthOfLine 200 #define NumberOfUniqueConnections 6 typedef struct _node *nodeptr; typedef struct _node { char *pair[2]; nodeptr next; } node; nodeptr OutputNodes = NULL; nodeptr InputNodes = NULL; /* getopt stuff */ extern int optind, getopt(); extern char *optarg; struct Buffers { struct Buffers *next; char in[LengthOfLine], out[LengthOfLine]; }; struct Clocks { struct Clocks *next; char in[LengthOfLine], out[LengthOfLine]; }; struct InputPorts { struct InputPorts *next; char port[LengthOfLine]; }; struct FlopCell { char *name; char *pin_in; char *pin_out; char *pin_clock; }; struct BufCell { char *name; char *pin_in; char *pin_out; }; int getlineloc( char s[], int lim, FILE *fp); struct Buffers *BufferAlloc(); struct Clocks *ClockAlloc(); struct InputPorts *CIAlloc(); void AddClocks( FILE *BDNETFILE ,struct Clocks *Clock, struct Buffers *Buffer, int, int, struct InputPorts *, struct BufCell *, struct FlopCell *); void ReadClockInput(FILE *INPUT, struct InputPorts *ClockedInput); void ReadGenlib(char *, struct BufCell *, struct FlopCell *); void helpmessage(); int NoClockInputs = TRUE; int main (int argc, char *argv[]) { FILE *NET1, *NET2, *OUT, *INPUTFILE; struct Buffers *Buffer; struct Clocks *Clock; struct InputPorts *ClockedInput; int i, AllMatched, NetsEqual, ImplicitPower, BuffersOn; char Net1name[LengthOfNodeName]; char *ClockedInputsFile = NULL; char *TechFile = NULL; struct BufCell bufCell; struct FlopCell flopCell; bufCell.name = NULL; flopCell.name = NULL; BuffersOn=TRUE; while ((i = getopt( argc, argv, "c:b:f:t:nxhH" )) != EOF ) { switch(i) { case 't': TechFile = strdup(optarg); break; case 'b': bufCell.name = strdup(optarg); break; case 'f': flopCell.name = strdup(optarg); break; case 'n': BuffersOn=FALSE; break; case 'c': ClockedInputsFile = strdup(optarg); break; case 'x': NoClockInputs=FALSE; break; case 'h': case 'H': helpmessage(); break; default: fprintf(stderr,"\nbad switch %d\n", i ); helpmessage(); break; } } if (optind < argc) { strcpy(Net1name, argv[optind]); optind++; } else { fprintf(stderr, "Couldn't find a filename as input\n"); exit(EXIT_FAILURE); } optind++; NET1 = fopen(Net1name, "r"); if (NET1 == NULL ) { fprintf(stderr, "Couldn't open %s for read\n", Net1name); exit(EXIT_FAILURE); } ClockedInput = CIAlloc(); ClockedInput->next = FALSE; if (ClockedInputsFile) { INPUTFILE = fopen(ClockedInputsFile, "r"); if (INPUTFILE == NULL) { fprintf(stderr, "Couldn't find file with inputs to clock: %s\n", ClockedInputsFile); exit(EXIT_FAILURE); } else { NoClockInputs = FALSE; ReadClockInput(INPUTFILE, ClockedInput); } } OUT = stdout; Clock = ClockAlloc(); Buffer = BufferAlloc(); if (!TechFile) TechFile = strdup("/pub/tech/IBM/verilog/IBM7RF.genlib"); ReadGenlib(TechFile, &bufCell, &flopCell); AddClocks(NET1, Clock, Buffer, BuffersOn, (ClockedInputsFile) ? 1 : 0, ClockedInput, &bufCell, &flopCell); if (ClockedInputsFile) free(ClockedInputsFile); if (TechFile) free(TechFile); if (bufCell.name) free(bufCell.name); if (bufCell.pin_in) free(bufCell.pin_in); if (bufCell.pin_out) free(bufCell.pin_out); if (flopCell.name) free(flopCell.name); if (flopCell.pin_in) free(flopCell.pin_in); if (flopCell.pin_out) free(flopCell.pin_out); if (flopCell.pin_clock) free(flopCell.pin_clock); return 0; } /*--------------------------------------------------------------------------------*/ /* Parse the genlib file to get the pin names for the buffer and flop/latch cells */ /*--------------------------------------------------------------------------------*/ void ReadGenlib(char *techName, struct BufCell *bufCell, struct FlopCell *flopCell) { FILE *inFile; char line[LengthOfLine]; char type[LengthOfLine]; char cellname[LengthOfLine]; char pin1[LengthOfLine]; char pin2[LengthOfLine]; char *scptr; int have_buffer = FALSE; int have_flop = FALSE; int need_control = FALSE; inFile = fopen(techName, "r"); if (inFile == NULL) { fprintf(stderr, "Error: Genlib file '%s' not found\n", techName); return; } while (getlineloc(line, sizeof(line), inFile) > 0) { if (sscanf(line, "%s %s", type, cellname) == 2) { if (!have_buffer && !strcmp(type, "GATE")) { if (need_control) need_control = FALSE; if (!strcmp(cellname, bufCell->name)) { if (sscanf(line, "%*s %*s %*g %s = %s", pin1, pin2) == 2) { bufCell->pin_out = strdup(pin1); if ((scptr = strchr(pin2, ';')) != NULL) *scptr = '\0'; bufCell->pin_in = strdup(pin2); have_buffer = TRUE; } else { fprintf(stderr, "Error: Gate %s found in %s, but definition:\n", bufCell->name, techName); fprintf(stderr, " '%s'\n", line); fprintf(stderr, "doesn't match expected syntax:\n"); fprintf(stderr, " 'GATE %s = ;\n", bufCell->name); break; } } } else if (!strcmp(type, "LATCH")) { if (need_control) need_control = FALSE; if (!have_flop && !strcmp(cellname, flopCell->name)) { if (sscanf(line, "%*s %*s %*g %s = %s", pin1, pin2) == 2) { flopCell->pin_out = strdup(pin1); if ((scptr = strchr(pin2, ';')) != NULL) *scptr = '\0'; flopCell->pin_in = strdup(pin2); need_control = TRUE; } else { fprintf(stderr, "Error: Latch %s found in %s, but definition:\n", flopCell->name, techName); fprintf(stderr, " '%s'\n", line); fprintf(stderr, "doesn't match expected syntax:\n"); fprintf(stderr, " 'LATCH %s = ;\n", bufCell->name); break; } } } else if (!strcmp(type, "CONTROL")) { if (need_control) { flopCell->pin_clock = strdup(cellname); need_control = FALSE; have_flop = TRUE; } } } } if (!have_buffer) { free(bufCell->name); bufCell->name = NULL; } if (!have_flop) { free(flopCell->name); flopCell->name = NULL; } } void ReadClockInput(FILE *INPUT, struct InputPorts *ClockedInput) { struct InputPorts *ClockedInputPresent; char line[LengthOfLine]; char port[LengthOfLine]; ClockedInputPresent=ClockedInput; while (getlineloc(line, sizeof(line), INPUT) > 0 ) { if (line[0] != '*') { if (sscanf(line, "%s", port) != 1) { fprintf(stderr, "problem reading clock input file :%s\n", line); } ClockedInputPresent->next = CIAlloc(); strcpy(ClockedInputPresent->port, port); ClockedInputPresent = ClockedInputPresent->next; ClockedInputPresent->next = NULL; } } } /* Check for net names changed due to an inserted flop */ void CheckClock(char *name, struct Clocks *Clock) { struct Clocks *ClockPresent; int nlen, NeedSemi = FALSE; nlen = strlen(name); if (name[nlen - 1] == ';') { NeedSemi = TRUE; name[nlen - 1] = '\0'; } for (ClockPresent = Clock; ClockPresent != NULL; ClockPresent = ClockPresent->next) { if (!strncmp(name, ClockPresent->in, nlen)) { sprintf(name, ClockPresent->out); if (NeedSemi) strcat(name, ";"); break; } } } /* Add output and (optionally) input buffers buffers */ void AddClocks( FILE *BDNETFILE ,struct Clocks *Clock, struct Buffers *Buffer, int BuffersOn, int ClockSomeInputs, struct InputPorts *ClockedInput, struct BufCell *bufCell, struct FlopCell *flopCell) { struct InputPorts *ClockedInputPresent; struct Clocks *ClockPresent; struct Buffers *BuffPresent; nodeptr newnode; int INPUTSection,OUTPUTSection, ADDIO; int AddClock2ThisOne; int LastInput = FALSE; int LastOutput = FALSE; char line[LengthOfLine]; char inlabel[LengthOfLine], innode[LengthOfLine]; char outlabel[LengthOfLine], outnode[LengthOfLine]; INPUTSection = FALSE; OUTPUTSection = FALSE; ADDIO = FALSE; ClockPresent = Clock; BuffPresent = Buffer; if (ClockSomeInputs) ClockedInputPresent = ClockedInput; while (getlineloc(line, sizeof(line), BDNETFILE) > 0) { if (strncmp(line,"INPUT",5) ==0 ) { fprintf(stdout,"INPUT\n"); INPUTSection=TRUE; OUTPUTSection=FALSE; } if (strncmp(line,"OUTPUT",6) ==0) { fprintf(stdout,"OUTPUT\n"); INPUTSection=FALSE; OUTPUTSection=TRUE; } if (strncmp(line,"INSTANCE",8) ==0) { INPUTSection=FALSE; OUTPUTSection=FALSE; } if (strncmp(line,"ENDMODEL",8) ==0 ) { if (bufCell->name != NULL && flopCell->name != NULL) ADDIO=TRUE; else fprintf(stderr, "Warning: No techfile information; cannot add buffers!\n"); } if (INPUTSection == TRUE) { AddClock2ThisOne = (NoClockInputs) ? FALSE : TRUE; if (sscanf(line,"%s : %s", inlabel, innode) == 2) { // Record this input node newnode = (nodeptr)malloc(sizeof(node)); newnode->pair[0] = strdup(inlabel); newnode->pair[1] = strdup(innode); newnode->next = InputNodes; InputNodes = newnode; if (ClockSomeInputs) { ClockedInputPresent = ClockedInput; AddClock2ThisOne = TRUE; while (ClockedInputPresent->next != NULL) { if (strstr(inlabel,ClockedInputPresent->port) != NULL) { AddClock2ThisOne = FALSE; } ClockedInputPresent = ClockedInputPresent->next; } } if (strcmp(inlabel,"\"clock\"") != 0 && AddClock2ThisOne) { ClockPresent->next = ClockAlloc(); if (innode[strlen(innode)-1] == ';') { LastInput = TRUE; innode[strlen(innode)-1] = '\0'; } if (!strcmp(inlabel, innode)) { /* Input node and label are the same. Change */ /* the input node whereever it occurs. */ char tempnode[256]; sprintf(tempnode, "\"int_%s", innode + 1); strcpy(innode, tempnode); } fprintf(stdout," %s\t :\t %s",inlabel,inlabel); if (LastInput) fprintf(stdout, ";"); fprintf(stdout, "\n"); strcpy(ClockPresent->in, inlabel); strcpy(ClockPresent->out, innode); ClockPresent = ClockPresent->next; ClockPresent->next = NULL; } else fprintf(stdout, "%s", line); } else if (sscanf(line, "%s", inlabel) == 1) ; // else fprintf(stderr,"Read Error in input \n"); } else if (OUTPUTSection == TRUE && BuffersOn) { if (sscanf(line,"%s : %s", outlabel, outnode) == 2) { if (outnode[strlen(outnode)-1] == ';') LastOutput = TRUE; CheckClock(outnode, Clock); BuffPresent->next = BufferAlloc(); strcpy(BuffPresent->in,outnode); strcpy(BuffPresent->out,outlabel); BuffPresent=BuffPresent->next; BuffPresent->next = NULL; fprintf(stdout, " %s\t :\t %s", outlabel,outlabel); if (LastOutput) fprintf(stdout, ";\n"); fprintf(stdout, "\n"); } else if (sscanf(line,"%s",outlabel) == 1) ; // else fprintf(stderr,"Read Error in output \n"); } /* No buffers---but record all of the internal output node names */ /* for replacement. If the internal node name is a system input, */ /* then we add a buffer anyway. */ else if (OUTPUTSection == TRUE) { if (sscanf(line, "%s : %s", outlabel, outnode) == 2) { if (outnode[strlen(outnode)-1] == ';') { LastOutput = TRUE; outnode[strlen(outnode) - 1] = '\0'; } fprintf(stdout, " %s\t :\t %s", outlabel, outlabel); if (LastOutput) fprintf(stdout, ";\n"); fprintf(stdout, "\n"); // Is outnode an input? If so, buffer it regardless of // whether or not buffers have been specified. for (newnode = InputNodes; newnode != NULL; newnode = newnode->next) { if (!strcmp(outnode, newnode->pair[1])) { strcpy(outnode, newnode->pair[0]); break; } } if (newnode == NULL) { newnode = (nodeptr)malloc(sizeof(node)); newnode->pair[0] = strdup(outlabel); newnode->pair[1] = strdup(outnode); newnode->next = OutputNodes; OutputNodes = newnode; } else { if (outnode[strlen(outnode)-1] == ';') LastOutput = TRUE; CheckClock(outnode, Clock); BuffPresent->next = BufferAlloc(); strcpy(BuffPresent->in,outnode); strcpy(BuffPresent->out,outlabel); BuffPresent=BuffPresent->next; BuffPresent->next = NULL; } } else if (sscanf(line, "%s", outlabel) == 1); // else fprintf(stderr,"Read Error in output \n"); } else if (ADDIO == TRUE) { BuffPresent = Buffer; while (BuffPresent->next != NULL) { fprintf(stdout, "INSTANCE \"%s\":\"physical\"\n", bufCell->name); fprintf(stdout, "\t\"%s\"\t : \t%s;\n", bufCell->pin_in, BuffPresent->in); fprintf(stdout, "\t\"%s\"\t : \t%s;\n", bufCell->pin_out, BuffPresent->out); fprintf(stdout, "\n"); BuffPresent = BuffPresent->next; } if (NoClockInputs == FALSE) { ClockPresent = Clock; while (ClockPresent->next != NULL) { fprintf(stdout, "INSTANCE \"%s\":\"physical\"\n", flopCell->name); fprintf(stdout, "\t\"%s\"\t : \t%s;\n", flopCell->pin_in, ClockPresent->in); fprintf(stdout, "\t\"%s\"\t : \t\"clock\";\n", flopCell->pin_clock); fprintf(stdout, "\t\"%s\"\t : \t%s;\n", flopCell->pin_out, ClockPresent->out); fprintf(stdout, "\n"); ClockPresent = ClockPresent->next; } } fprintf(stdout,"ENDMODEL;\n"); } else { if (sscanf(line, "%s : %s", outlabel, outnode) == 2) { CheckClock(outnode, Clock); /* Do output name replacement, if output name matches */ for (newnode = OutputNodes; newnode != NULL; newnode = newnode->next) { if (!strcmp(outnode, newnode->pair[1])) { strcpy(outnode, newnode->pair[0]); break; } } fprintf(stdout, "%s : %s\n", outlabel, outnode); } else fprintf(stdout, "%s", line); } } } /*--------------------------------------------------------------*/ /* C getlineloc: read a line, return length */ /* */ /* ARGS: */ /* RETURNS: 1 to OS */ /* SIDE EFFECTS: */ /*--------------------------------------------------------------*/ int getlineloc(char s[], int lim, FILE *fp) { int c, i; i=0; while(--lim > 0 && (c=getc(fp)) != EOF && c != '\n') s[i++] = c; if (c == '\n'); s[i++] = c; s[i] = '\0'; if ( c == EOF ) i=0; return i; } struct Buffers *BufferAlloc() { return (struct Buffers *)malloc( sizeof(struct Buffers)); } struct Clocks *ClockAlloc() { return (struct Clocks *)malloc(sizeof(struct Clocks)); } struct InputPorts *CIAlloc() { return (struct InputPorts *)malloc(sizeof(struct InputPorts)); } void helpmessage() { fprintf(stderr, "AddIO2Bdnet [-options] bdnetfile\n"); fprintf(stderr, "takes a bdnet file as input and adds double buffers\n"); fprintf(stderr, "to the outputs and D-flops to all inputs. Output on stdout.\n"); fprintf(stderr, "\nThe option -b 'buffername' uses the cell named 'buffername'\n"); fprintf(stderr, "for buffer cells.\n"); fprintf(stderr, "\nThe option -f 'flopname' uses the cell named 'flopname'\n"); fprintf(stderr, "for clocked latches or flip-flops.\n"); fprintf(stderr, "\nThe option -n does not add buffers to the output.\n"); fprintf(stderr, "The option -x adds clocked latches to all inputs.\n"); fprintf(stderr, "\nThe option -c 'filename', only clocks those inputs found " "in 'filename'\n"); fprintf(stderr, "The format in filename is one input port per line and " "comments are\n"); fprintf(stderr, "allowed on lines starting with a *\n"); fprintf(stderr, "Furthermore, an input port found in 'filename' that partially\n"); fprintf(stderr, "matches an input port in the netlist will not be clocked\n"); fprintf(stderr, "This means that for buses, only the body need to be " "in 'filename'\n"); fprintf(stderr, "and the whole bus will be excluded\n"); fprintf(stderr, "\nVersion 0.04 SB/TE/PkK 2009-07-13\n"); exit(EXIT_HELP); }