/**************************************************************************** Copyright (C) 1987-2015 by Jeffery P. Hansen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Last edit by hansen on Thu Feb 12 14:49:29 2009 ****************************************************************************/ #include #include #include #include #include #include #include "tkgate.h" static SHash *GateTypeHash = 0; /* Map from new style gate type names to gateinfo */ static SHash *OldGateTypeHash = 0; /* Map from old verilog name to gateinfo */ NHash *GateIdxHash = 0; /* Map from gate type code to gateinfo */ Icon *INVERTER; /* Icon for inverter buble */ Icon *Mark; /* Icon for position mark */ Icon *SIZEHASH; /* Icon for wire bit size hash mark */ Icon *REPCOUNTMARK; /* Icon for replicate mark */ int GlobalElementCount = 0; /* Global counter of gate elements */ /***************************************************************************** * * Table for IO direction marks for pins on logic blocks. Note, these arrows * are also shared by concat elements. * *****************************************************************************/ static Icon *iodmark[4][4]; /* Normal arrows [orient][iodir] */ static Icon *boxmark[4][4]; /* Boxed arrows [orient][iodir] */ /***************************************************************************** * * Set the name of a gate in a module * * Parameters: * g Gate on which to change/set name. * name New name for gate. * M Module in which gate is defined (null if gate is not * yet in defined in a module). * *****************************************************************************/ void gate_setName(GCElement *g,const char *name,GModuleDef *M) { char buf[1024]; SHash *H = M ? M->m_gates : 0; if (name && g->ename && strcmp(name,g->ename) == 0) return; pickValidName(buf,name,"g",H); if (g->ename) { SHash_remove(H,g->ename); ob_free(g->ename); } ob_touch(g); g->ename = ob_strdup(buf); g->show_name = (name != 0); if (H) SHash_insert(H,g->ename,g); } /***************************************************************************** * * Add a gate to a module. * * Parameters: * M Module in which gate will be placed * g Gate to be added. * *****************************************************************************/ void gate_add(GModuleDef *M,GCElement *g) { if (!g->ename) { ob_touch(g); gate_setName(g,0,M); g->show_name = 0; } } /***************************************************************************** * * Remove a gate from a module. * * Parameters: * M Module in which gate is currently defined. * g Gate to remove from module. * *****************************************************************************/ void gate_remove(GModuleDef *M,GCElement *g) { SHash_remove(M->m_gates,g->ename); } /***************************************************************************** * * Creates a new gate object. * * Parameters: * x,y Position for new gate. * rot Initial rotation for new gate. * type Type of new gate. * * Returns: New gate object (not yet inserted into a module) * *****************************************************************************/ GCElement *gate_new(int x,int y,int rot,int type) { GGateInfo *ginfo = GGateInfo_codeLookup(type); GCElement *g; int i,n; int N; #ifdef DEBUG printf("gate_new(%d %d %d NULL)\n",x,y,type); #endif g = (GCElement *) ob_malloc(sizeof(GCElement)+requiredPortMemory(ginfo->NumPads),"GCElement"); memset(g,0,sizeof(*g)); g->typeinfo = ginfo; g->tech = ob_strdup(TKGATE_DEFAULT_TECH); g->xpos = x; g->ypos = y; g->top = 0; g->bottom = 0; g->selected = 0; g->orient = g->typeinfo->Flags.CanRot ? rot : 0; g->ename = 0; g->show_name = 0; g->anchored = 0; g->cust_delay = 0; g->isModuleInterface = 0; g->cpath_cut = 0; g->enumb = GlobalElementCount++; N = GCElement_numPads(g); for (i = 0;i < N;i++) g->wires[i] = NULL; if (g->typeinfo->InitGate) (*g->typeinfo->InitGate)(g); n = 0; for (i = 0;g->typeinfo->delayNames[i];i++)n++; if (n == 0) g->delays = 0; else { g->delays = (int*) ob_malloc(sizeof(int)*n,"int[]"); for (i = 0;g->typeinfo->delayNames[i];i++) g->delays[i] = 1; } return g; } /***************************************************************************** * * Unattach a wire from a gate. * * Parameters: * w Wire to detach (gate is assumed) * M Module in which wire is defined. * drawp Non-zero if we should update the display after operation. * *****************************************************************************/ void gate_unattachwire(GWire *w,GModuleDef *M,int drawp) { struct wire *wd; ob_touch(w); ob_touch(w->gate); wd = w->driver; if (M && drawp) GWire_draw(wd); w->gate = NULL; if (w->name) ob_free(w->name); w->name = NULL; #if 0 if (!wire_trash(w->nodes,M,drawp)) { w->invert = 0; if (M && drawp) GWire_draw(wd); } else { if (M) { ob_touch(M); M->m_wires = wire_unlink(M->m_wires,w); } wire_free(w); } #else if (!wire_nuke(w,drawp,M)) { w->invert = 0; if (M && drawp) GWire_draw(wd); } #endif } /***************************************************************************** * * Unattach all wires from a pad of a gate. * * Parameters: * w Head of pad list on a gate * M Module in which to perform opreration * drawp Non-zero if we should update display. * *****************************************************************************/ void gate_unattachwirelist(GWire *w,GModuleDef *M,int drawp) { GWire *wnext; for (;w;w = wnext) { wnext = w->next; gate_unattachwire(w,M,drawp); } } /***************************************************************************** * * Cut all wires off of a gate. * * Parameters: * g Gate to strip of all wires. * M Module in which gate is defined/ * drawp Non-zero if we should update display. * *****************************************************************************/ void gate_cutOffWires(GCElement *g,GModuleDef *M,int drawp) { int i; int N = GCElement_numPads(g); ob_touch(g); for (i = 0;i < N;i++) { gate_unattachwirelist(g->wires[i],M,drawp); g->wires[i] = NULL; } } /***************************************************************************** * * Delete a gate. * * Parameters: * g Gate to be deleted. * M Module in which gate is currently defined. * drawp Non-zero if we should update the display. * * Returns: Non-zero on success. * * Delete a gate by unattaching all wires connected to it and removing it from * the object list. This function does not actually free the object. * *****************************************************************************/ int gate_delete(GCElement *g,GModuleDef *M,int drawp) { #if 0 if (g->typeinfo != (void*)0xa7a7a7a7) printf("gate_delete(%p: %s %s)\n",g,g->typeinfo->name,g->ename); else { printf("gate_delete(%p: bogus)\n",g); abort(); } #endif (*g->typeinfo->DeleteGate)(g,M,drawp); ob_free(g); /* g->typeinfo = 0; */ return 1; } /***************************************************************************** * * Auxilary function to do a hit test to detect a gate. * * Parameters: * x,y Position of the "hit". * M Module to search * * Returns: The best gate for a hit at (x,y) * *****************************************************************************/ GCElement *gate_hit(GModuleDef *M,int x,int y) { int threshDist = GATERANGE; HashElem *gl; GCElement *hit = 0; for (gl = Hash_first(M->m_gates);gl;gl = Hash_next(M->m_gates,gl)) { GCElement *g = (GCElement*) HashElem_obj(gl); int dist; dist = (*g->typeinfo->HitDistance)(g,x,y); if (dist < threshDist) { hit = g; threshDist = dist; } } return hit; } /***************************************************************************** * * Displays all the gates in a module * * Parameters: * M Module to be displayed. * *****************************************************************************/ void gate_displayall(GModuleDef *M) { HashElem *gl; GWireList *wl; for (gl = Hash_first(M->m_gates);gl;gl = Hash_next(M->m_gates,gl)) { int MinX,MinY,MaxX,MaxY; GCElement *g = (GCElement*) HashElem_obj(gl); gate_draw(g,GD_NOWIRE); gate_getbbx(g,TD_X11,&MinX,&MinY,&MaxX,&MaxY); if (MinX < TkGate.ed->min_x) TkGate.ed->min_x = MinX; if (MinY < TkGate.ed->min_y) TkGate.ed->min_y = MinY; if (MaxX > TkGate.ed->max_x) TkGate.ed->max_x = MaxX; if (MaxY > TkGate.ed->max_y) TkGate.ed->max_y = MaxY; } for (wl = M->m_wires;wl;wl = wl->wl_next) { GWire *w = wl->wl_wire; if (w == w->driver) GWire_draw(w); } } /* Draws a gate (Circuit element) and the wires connected to it. */ void gate_draw(GCElement *g,int md) { if (g->typeinfo->DrawGate) (*g->typeinfo->DrawGate)(g,md); else Generic_Draw(g,md); } void gate_drawWires(GCElement *g,int md) { GWire *w; int i; int N = GCElement_numPads(g); if (md != GD_NOWIRE) { for (i = 0;i < N;i++) for (w = g->wires[i];w;w=w->next) if (w->nodes->out) { GWire_draw(w); } else { if ((w->driver->gate != g) && !(w->driver->gate && md == GD_NOINWIRE)) GWire_draw(w->driver); } } } void gate_drawgatename(GCElement *g,const char *name) { int x,y; int o; o = g->orient; x = g->xpos; y = g->ypos; if (g->selected) XSetFont(TkGate.D,TkGate.instGC,TkGate.textbXF[TkGate.circuit->zoom_factor]->fid); else XSetFont(TkGate.D,TkGate.instGC,TkGate.textXF[TkGate.circuit->zoom_factor]->fid); dce_DrawString(TkGate.instGC,x + g->typeinfo->lpos[o].x, y + g->typeinfo->lpos[o].y, g->typeinfo->lpos[o].just,name); } /* Moves a gate and adjusts wires */ void gate_move(GCElement *g,int dx,int dy) { if (GModuleDef_isDataProtected(TkGate.circuit->es->env)) { message(0,msgLookup("err.protdata")); return; } if (g->anchored) { message(0,msgLookup("err.gatanchor")); /* "Gate is anchored and can not be moved." */ return; } SetModified(MF_NET|MF_GATE); (*g->typeinfo->MoveGate)(g,dx,dy); } /***************************************************************************** * * Move an object by the specified amount (specified as a relative position) * *****************************************************************************/ void gate_moveObject(GCElement *g,int dx,int dy) { if (g->anchored) { message(0,msgLookup("err.gatanchor")); /* "Gate is anchored and can not be moved." */ return; } gate_draw(g,GD_NORMAL); gate_move(g,dx,dy); gate_draw(g,GD_NORMAL); } void gate_moveTo(GCElement *g,int x,int y) { gate_move(g,x-g->xpos,y-g->ypos); } /* Marks a gate */ void gate_mark(GCElement *g,int select) { ob_touch(g); g->selected = select; } /* Gets the bounding box of a gate. */ void gate_getbbx(GCElement *g,TargetDev_e target, int *minx,int *miny,int *maxx,int *maxy) { (*g->typeinfo->GetExtents)(g, target, minx,miny,maxx,maxy,0); } void displayRepCount(int x,int y,int num) { char ns[30]; Icon_draw(TkGate.D,TkGate.W,TkGate.toolGC,ctow_x(x),ctow_y(y),REPCOUNTMARK); sprintf(ns,"%d",num); dce_DrawString(TkGate.toolGC,x+10,y,BetweenTopAndBottom|AtLeft,ns); } void gate_doReplication(EditState *es) { struct celemnt *g; int sx,sy,ex,ey,dx,dy,h,w,n,bd,num; g = TkGate.circuit->select; ZDrawLine(TkGate.D,TkGate.W,TkGate.toolGC,ctow_x(TkGate.ed->sx),ctow_y(TkGate.ed->sy),ctow_x(TkGate.ed->tx),ctow_y(TkGate.ed->ty)); (*g->typeinfo->GetExtents)(g,TD_X11,&sx,&sy,&ex,&ey,&bd); w = ex-sx + bd; h = ey-sy + bd; sx = g->xpos; sy = g->ypos; ex = TkGate.ed->tx; ey = TkGate.ed->ty; if (sx == ex) { dx = 0; dy = (sy > ey) ? -h : h; n = abs((sy-ey)/dy); } else if (sy == ey) { dx = (sx > ex) ? -w : w; dy = 0; n = abs((sx-ex)/dx); } else if (abs(10*(sy-ey)/(sx-ex)) > (10*h)/w) { dy = (sy > ey) ? -h : h; dx = (dy*(sx-ex))/(sy-ey); n = abs((sy-ey)/dy); } else { dx = (sx > ex) ?-w : w; dy = (dx*(sy-ey))/(sx-ex); n = abs((sx-ex)/dx); } sx += dx; sy += dy; num = 2; while (n--) { GCElement *ng; displayRepCount(sx,sy,num); ng = (*g->typeinfo->CopyGate)(es->env,g,sx,sy,0); gate_draw(ng,0); sx += dx; sy += dy; num++; } } void gate_setinvertwirelist(GWire *nw,GWire *w) { for (;nw && w;w = w->next,nw = nw->next) { ob_touch(nw); nw->invert = w->invert; } } void gate_hashrepline(EditState *es,int x,int y) { GCElement *g; int sx,sy,ex,ey,dx,dy,bd,h,w,n,num; g = TkGate.circuit->select; (*g->typeinfo->GetExtents)(g,TD_X11,&sx,&sy,&ex,&ey,&bd); w = ex-sx + bd; h = ey-sy + bd; sx = g->xpos; sy = g->ypos; ex = x; ey = y; if (sx == ex) { dx = 0; dy = (sy > ey) ? -h : h; n = abs((sy-ey)/dy); } else if (sy == ey) { dx = (sx > ex) ? -w : w; dy = 0; n = abs((sx-ex)/dx); } else if (abs(10*(sy-ey)/(sx-ex)) > (10*h)/w) { dy = (sy > ey) ? -h : h; dx = (dy*(sx-ex))/(sy-ey); n = abs((sy-ey)/dy); } else { dx = (sx > ex) ? -w : w; dy = (dx*(sy-ey))/(sx-ex); n = abs((sx-ex)/dx); } sx += dx; sy += dy; num = 2; while (n--) { displayRepCount(sx,sy,num); sx += dx; sy += dy; num++; } } int GGateInfo_getPadNum(GGateInfo *gi,const char *pname) { char buf[STRMAX]; int p; if (sscanf(pname,"%[A-Za-z]",buf) != 1) return -1; for (p = 0;p < gi->NumPads;p++) if (strcmp(gi->Pad[p].name,buf) == 0) return p; return -1; } /* Transmute a gate from one type to another. Warning: Only certain types of transmutations can be performed. */ void gate_transmute(GCElement *g,GGateInfo *ngi) { GGateInfo *ogi = g->typeinfo; int oldOrient,rot,i; assert(ngi->NumPads == ogi->NumPads); ob_touch(g); oldOrient = g->orient; rot = ogi->Pad[0].Loc[oldOrient].dir; for (i = 0;i < 4;i++) if (ngi->Pad[0].Loc[i].dir == rot) { g->orient = i; break; } assert(i != 4); for (i = 0;i < ngi->NumPads;i++) { GWire *w; GPadLoc *oL = &ogi->Pad[i].Loc[oldOrient]; GPadLoc *nL = &ngi->Pad[i].Loc[g->orient]; for (w = g->wires[i];w;w = w->next) { ob_touch(w->nodes); w->nodes->x += nL->x1 - oL->x1; w->nodes->y += nL->y1 - oL->y1; } } g->typeinfo = ngi; } /***************************************************************************** * * Get number of pads on a gate. * * Paramaters: * g Gate to examine for pad count * * Returns: Number of pads on g * * Return the number of pads on a gate. For all gate types except symbol * modules we get this from the gate's typeinfo object. For symbol modules, * we use the symbol data. * *****************************************************************************/ int GCElement_numPads(GCElement *g) { extern GGateInfo gate_symblock_info; if (g->typeinfo == &gate_symblock_info) { if (g->u.block.symbol) return GModSymbol_numPorts(g->u.block.symbol); else return 0; } else return g->typeinfo->NumPads; } GPadLoc *GCElement_getPadLoc(GCElement *g,int p,int r) { extern GGateInfo gate_symblock_info; if (g->typeinfo == &gate_symblock_info) { GSymPort *sp = GModSymbol_getPort(g->u.block.symbol,p); return &sp->msp_loc[r]; } else return &g->typeinfo->Pad[p].Loc[r]; } int GCElement_getPadDir(GCElement *g,int p) { extern GGateInfo gate_symblock_info; if (g->typeinfo == &gate_symblock_info) { GSymPort *sp = GModSymbol_getPort(g->u.block.symbol,p); return sp->msp_type; } else return g->typeinfo->Pad[p].iotype; } /***************************************************************************** * * Get the name of the pth pad. * * Parameters: * g Gate in on which we are looking up the pad name. * p Index of pad * *****************************************************************************/ const char *GCElement_getPadName(GCElement *g,int p) { extern GGateInfo gate_symblock_info; if (g->typeinfo == &gate_symblock_info) { GSymPort *sp = GModSymbol_getPort(g->u.block.symbol,p); return sp->msp_name; } else return g->typeinfo->Pad[p].name; } /***************************************************************************** * * Get the wire associated with the named pad on a gate * * Parameters: * g Gate * portName Index of pad * *****************************************************************************/ GWire *GCElement_getPort(GCElement *g, const char *portName) { int n = GCElement_numPads(g); GWire *w; int i; if (GCElement_getType(g) == GC_BLOCK) { for (i = 0;i < n;i++) for (w = g->wires[i];w;w = w->next) if (strcmp(w->name,portName) == 0) return w; } else if (GCElement_getType(g) == GC_SYMBLOCK) { for (i = 0;i < n;i++) { GSymPort *sp = GModSymbol_getPort(g->u.block.symbol,i); if (strcmp(sp->msp_name, portName) == 0) return g->wires[i]; } } else { GGateInfo *gi = g->typeinfo; int k = 0; i = GGateInfo_getPadNum(gi,portName); if (sscanf(portName+strlen(gi->Pad[i].name),"%d",&k) != 1) k = 0; for (w = g->wires[i];k > 0 && w;w = w->next, k--); return w; } return 0; } int GCElement_getPadCanAdd(GCElement *g,int p) { extern GGateInfo gate_symblock_info; if (g->typeinfo == &gate_symblock_info) { return 0; } else return g->typeinfo->Pad[p].CanAdd; } /***************************************************************************** * * Set the symbol to use for a symbol block module. * * Parameters: * g Gate on which to set symbol (must be a SYMBLOCK) * ms Symbol to set for gate. * *****************************************************************************/ void GCElement_setSymbol(GCElement *g, GModSymbol *ms) { ob_touch(g); if (g->u.block.symbol) { GModSymbol_detach(g->u.block.symbol); } g->u.block.symbol = ms; if (ms) { GModSymbol_attach(ms); } } /***************************************************************************** * * Lookup function for new-style gate type names. * * Parameters: * name Name to look up. * * Returns: Gate info object corresponding to name * *****************************************************************************/ GGateInfo *GGateInfo_lookup(const char *name) { return (GGateInfo*) SHash_find(GateTypeHash,name); } /***************************************************************************** * * Lookup function for old-style gate type names. * * Parameters: * name Name to look up. * * Returns: Gate info object corresponding to name * *****************************************************************************/ GGateInfo *GGateInfo_vlookup(const char *name) { return (GGateInfo*) SHash_find(OldGateTypeHash,name); } /***************************************************************************** * * Lookup function for old-style gate type variant numbers. * * Parameters: * gi Gate info for gate type. * name Name to look up. * * Returns: Variant number corresponding to name. * *****************************************************************************/ int GGateInfo_variantNum(GGateInfo *gi,const char *func) { int vn = 0; char *p; int L = strlen(func); for (p = gi->vnames;p && *p;vn++,p = strchr(p+1,':')) { if (*p == ':') p++; if (strncmp(p,func,L) == 0 && (p[L] == ':' || !p[L])) break; } return vn; } /***************************************************************************** * * Registers a gate type * * Parameters: * gi Gate info object to be registered. * *****************************************************************************/ void RegisterGate(GGateInfo *gi) { static int code_count = 1; char buf[STRMAX],*T; if (gi->code <= 0) gi->code = code_count++; if (!gi->vnames) { fprintf(stderr,"No verilog name for block '%s'\n",gi->name); exit(1); } strcpy(buf,gi->vnames); for (T = strtok(buf,":");T;T = strtok(0,":")) { SHash_insert(OldGateTypeHash,T,gi); } SHash_insert(GateTypeHash,gi->name,gi); NHash_insert(GateIdxHash,gi->code,gi); } /***************************************************************************** * * Initialize special icons if we are running in interactive mode. * *****************************************************************************/ void init_specials(void) { if (TkGate.tcl) { Pixmap P; Icon *ico; P = Pixmap_registerFromFile("misc","misc.b"); Mark = new_Icon(P,6,28,9,9,4,4); SIZEHASH = new_Icon(P,16,27,10,10,4,4); INVERTER = new_Icon(P,0,28,5,5,2,2); REPCOUNTMARK = new_Icon(P,32,0,9,9,4,4); /***************************************************************************** * Register pixmaps for arrows *****************************************************************************/ P = Pixmap_registerFromFile("iodarrow","iodarrow.b"); ico = new_Icon(P,14,0,7,5,3,2); /* <> arrow */ iodmark[0][TRI] = iodmark[2][TRI] = ico; ico = new_Icon(P,14,6,5,7,2,3); /* v^ arrow */ iodmark[1][TRI] = iodmark[3][TRI] = ico; ico = new_Icon(P,22,0,5,5,2,2); /* x mark */ iodmark[0][ANY] = iodmark[1][ANY] = iodmark[2][ANY] = iodmark[3][ANY] = ico; ico = new_Icon(P,0,0,7,5,2,3); /* < arrow */ iodmark[0][IN] = iodmark[2][OUT] = ico; ico = new_Icon(P,6,8,7,5,3,2); /* > arrow */ iodmark[0][OUT] = iodmark[2][IN] = ico; ico = new_Icon(P,8,0,5,7,2,3); /* v arrow */ iodmark[1][IN] = iodmark[3][OUT] = ico; ico = new_Icon(P,0,6,5,7,2,3); /* ^ arrow */ iodmark[1][OUT] = iodmark[3][IN] = ico; /***************************************************************************** * Register pixmaps for boxed arrows *****************************************************************************/ P = Pixmap_registerFromFile("boxarrow","boxarrow.b"); ico = new_Icon(P,24,0,11,11,5,5); /* <> arrow */ boxmark[0][ANY] = boxmark[0][TRI] = boxmark[2][ANY] = boxmark[2][TRI] = ico; ico = new_Icon(P,24,12,11,11,5,5); /* v^ arrow */ boxmark[1][ANY] = boxmark[1][TRI] = boxmark[3][ANY] = boxmark[3][TRI] = ico; ico = new_Icon(P,0,0,11,11,5,5); /* < arrow */ boxmark[0][IN] = boxmark[2][OUT] = ico; ico = new_Icon(P,12,0,11,11,5,5); /* > arrow */ boxmark[0][OUT] = boxmark[2][IN] = ico; ico = new_Icon(P,12,12,11,11,5,5); /* v arrow */ boxmark[1][IN] = boxmark[3][OUT] = ico; ico = new_Icon(P,0,12,11,11,5,5); /* ^ arrow */ boxmark[1][OUT] = boxmark[3][IN] = ico; } } /***************************************************************************** * * Make the basic gate type info hash tables and initialize special objects * *****************************************************************************/ void init_gateHashTables(void) { GateTypeHash = new_SHash(); OldGateTypeHash = new_SHash(); GateIdxHash = new_SHash(); } /***************************************************************************** * * Lookup the gate info object from a type code * * Parameters: * T Type code to translate to a gate info object. * *****************************************************************************/ GGateInfo *GGateInfo_codeLookup(int T) { return (GGateInfo*) NHash_find(GateIdxHash,T); } /***************************************************************************** * * Generate type name for primitive of a particular gate type. * * Parameters: * buf Buffer to write type name to. * g Gate from which to generate a type. * * Built-in tkgate modules have a special naming convension. Here is * an example: * * _GGNAND3B4D5 g1 (.Z(w1), .I0({{4}{w2}}), .I1(w3), .I2(w4)); * * Here _GG is the prefix for built-in gates, the next "N" means that the * output is inverted, "AND" is the base name of the gate, "3" indicates * the number of inputs (or outputs depending on type), "B4" indicates the * base bit width and "D5" indicates the delay of the gate. * * The general format is: * * _GGx * * The meanings of the parts are: * * Output inverter state. A single leading "N" means * that all outputs are inverted. If this field is * omitted it means that all outputs are non-inverted. * For all other cases a string such as "NPPNN_" is used * to indicate the inverter status of each output port. * * This is the base name of the element. It must be one * of the tkgate defined primitive names. * * For primitives that have a variable number of ports on * one of their pads, this is the port count. This field * is omitted if the primitive has a fixed number of ports. * * This is the bit width of the gate if there are multiple * bit widths and the bit width is greater than 1. Note * that if the field was omitted, the "x" preceeding * this field is omitted. * * A delay specification prefixed by "_D" if explicit values * are given, by "_T" if a technology is given or omitted * if from the default technology. * * If a gate has parameters, this string encodes the parameter * values beginning with a _P. * * Examples: * * _GGNAND3x4_D5 3-input 4-bit wide AND gate with inverted output and * delay of 5. * * _GGOR4x8 4-input 8-bit wide OR gate with standard delay. * * _GGOR4x8_Tmytech 4-input 8-bit wide OR gate with delay from "mytech". * * _GGADD8_D68_70_62_64 8-bit adder with custom delay parameters of 68, 70, 62 and 64. * * _GGCLOCK_P100_0_50 Clock with pulsewidth of 100, phase of 0 and duty cycle of 50. * * Specical case examples: * * _GGRAM8x16 Ram with 8-bit address line and 16-bit data line. * * *****************************************************************************/ void GGateInfo_encodeTypeName(char *buf,GCElement *g) { GGateInfo *gi = g->typeinfo; int npad,nbit; char inv[STRMAX],*iq; unsigned inv_flags = 0; char *p; int i; /* * Get number of bits (or -1) if this gate has constant bit size. */ if (gi->gi_bitPad >= 0) { GWire *w; nbit = 0; for (w = g->wires[gi->gi_bitPad];w;w = w->next) if (nbit < w->net->n_nbits) nbit = w->net->n_nbits; } else nbit = -1; /* * Get port count variable for gate (or -1 if port count is fixed) */ if (gi->gi_multiPad >= 0) { GWire *w; npad = 0; for (w = g->wires[gi->gi_multiPad];w;w = w->next) npad++; } else npad = -1; /* * Genrate standard prefix */ p = buf; p += sprintf(p,"%s",TkGate.circuit->c_gatePrefix); /* * Generate output inverter sequence. */ iq = inv; inv_flags = 0; for (i = 0;i < gi->NumPads;i++) { if (gi->Pad[i].iotype != IN) { GWire *w; for (w = g->wires[i];w;w = w->next) { if (w->invert) { *iq++ = 'N'; inv_flags |= 1; } else { *iq++ = 'P'; inv_flags |= 2; } } } } *iq = 0; if (inv_flags == 1) p += sprintf(p,"N"); /* All outputs inverted, just attach an N */ else if (inv_flags == 3) p += sprintf(p,"%s_",inv); /* Mixed inverted and non-inverted outputs */ /* * Generate gate base name */ p += sprintf(p,"%s",gi->name); /* * Gate type specific modifictions. Eventually this should function should be * made into a a gateinfo "virtual" function. */ if (strcmp(gi->name,"RAM") == 0 || strcmp(gi->name,"ROM") == 0) { npad = g->wires[0]->net->n_nbits; /* Address line bits */ nbit = g->wires[1]->net->n_nbits; /* Data line bits */ } /* * Generate number of ports and bits */ if (npad >= 0) p += sprintf(p,"%u",npad); if (nbit > 1) { if (npad >= 0) p += sprintf(p,"x%u",nbit); else p += sprintf(p,"%u",nbit); } /* * Generate delay codes */ #if 0 if (g->cust_delay) { for (i = 0;gi->delayNames[i];i++) { if (i == 0) p += sprintf(p,"_D"); else p += sprintf(p,"_"); p += sprintf(p,"%u",g->delays[i]); } } else { if (strcmp(g->tech,TKGATE_DEFAULT_TECH) != 0) p += sprintf(p,"_T%s",g->tech); } #endif /* * Gate type specific modifictions. Eventually this should be moved into * a gateinfo function. */ if (strcmp(gi->name,"CLOCK") == 0) { p += sprintf(p,"_P%u_%u_%u",g->u.clock.omega,g->u.clock.phi,g->u.clock.duty); } } /***************************************************************************** * * Decode a gate name and return non-zero if it is a built-in type. * * Parameters: * name Name of cell from verilog file * gcs Special structure with cell name decoding. * * Returns: Non-zero if cell name was decoded. * * *****************************************************************************/ int GGateInfo_decodeTypeName(const char *name,GCellSpec *gcs) { char baseName[STRMAX]; char dpSpec[STRMAX]; /* Delay an parameter specifications */ int len = strlen(TkGate.circuit->c_gatePrefix); int n1,n2,i; int has_multipad = 0; int what; char *t; strcpy(gcs->gc_name,name); /* * If we don't have the right prefix, quite right now. */ if (strncmp(name,TkGate.circuit->c_gatePrefix,len) != 0) return 0; /* * Advance past prefix and look for a complex inverter specification. */ name += len; if (sscanf(name,"%[NP]_%s",gcs->gc_invSpec,baseName) == 2) { name += strlen(gcs->gc_invSpec)+1; } else *gcs->gc_invSpec = 0; /* Normal or no inverter spec */ /* * Copy prefix stripped name */ if (sscanf(name,"%[A-Za-z]%dx%d_%s",baseName,&n1,&n2,dpSpec) == 4) { } else if (sscanf(name,"%[A-Za-z]%d_%s",baseName,&n1,dpSpec) == 3) { n2 = -1; } else if (sscanf(name,"%[A-Za-z]_%s",baseName,dpSpec) == 2) { n1 = n2 = -1; } else if (sscanf(name,"%[A-Za-z]%dx%d",baseName,&n1,&n2) == 3) { *dpSpec = 0; } else if (sscanf(name,"%[A-Za-z]%d",baseName,&n1) == 2) { *dpSpec = 0; n2 = -1; } else if (sscanf(name,"%[A-Za-z]",baseName) == 1) { *dpSpec = 0; n1 = n2 = -1; } else return 0; /* Can not decode gate type name */ /* * Try to look up the gate type, if we do not find it, see if it has a leading N. */ gcs->gc_info = GGateInfo_lookup(baseName); if (!gcs->gc_info && *baseName == 'N' && !*gcs->gc_invSpec) { gcs->gc_info = GGateInfo_lookup(baseName+1); strcpy(gcs->gc_invSpec,"N"); } if (!gcs->gc_info) return 0; /* * Test to see if we have a multi-port on this type */ for (i = 0;i < gcs->gc_info->NumPads;i++) if (gcs->gc_info->Pad[i].CanAdd) { has_multipad = 1; break; } /* * If the gate has a "multipad" or it is a ROM or a RAM use n1 for the multi-pad size * and n2 for the bit size. In all other cases there is no multipad and we use n1 * for the number of bits. */ if (has_multipad || strcmp(gcs->gc_info->name,"ROM") == 0 || strcmp(gcs->gc_info->name,"RAM") == 0) { gcs->gc_multiPad = n1; gcs->gc_numBits = n2; } else { gcs->gc_multiPad = -1; gcs->gc_numBits = n1; } if (gcs->gc_numBits < 0) gcs->gc_numBits = 1; /* * Initialize the delay and parameter arrays. */ gcs->gc_numParms = 0; for (i = 0;i < MAXPARMS;i++) { gcs->gc_parms[i] = 1; } #if 0 gcs->gc_numDelays = 0; for (i = 0;gcs->gc_info->delayNames[i];i++) { gcs->gc_delays[i] = 1; } #endif #if 1 /* * Parse delay and parameter section. */ what = 0; for (t = strtok(dpSpec,"_");t;t = strtok(0,"_")) { if (isalpha(*t)) what = *t++; switch (what) { #if 0 case 'D' : if (gcs->gc_numDelays >= MAXDELAYS) break; if (sscanf(t,"%d",&n1) == 1) gcs->gc_delays[gcs->gc_numDelays++] = n1; break; case 'T' : { GDelayDef *dd; dd = GDelayDef_findTech(gcs->gc_info->delay_defs, t); if (!dd) break; gcs->gc_numDelays = GDelayDef_getDelaysFromCell(dd, gcs, gcs->gc_delays); } break; #endif case 'P' : if (gcs->gc_numParms >= MAXPARMS) break; if (sscanf(t,"%d",&n1) == 1) gcs->gc_parms[gcs->gc_numParms++] = n1; break; } } #endif return 1; } /***************************************************************************** * * Get icon data for displaying a directional arrow. * *****************************************************************************/ void GetPinIOMark(GWire *w,int d,int iod,int atype,int *x,int *y,Icon **arrow) { int dx,dy; *x = w->nodes->x; *y = w->nodes->y; switch (atype) { case IODT_PORT : *arrow = iodmark[d][iod]; dx = 4; dy = 5; break; case IODT_PLAIN : *arrow = iodmark[d][iod]; dx = 8; dy = 5; break; //case IODT_BOXED : default: *arrow = boxmark[d][iod]; dx = 12; dy = 7; break; } switch (d) { case D_UP : *x += dx; *y -= dy; break; case D_DOWN : *x += dx; *y += dy; break; case D_LEFT : *x -= dy; *y += dx; break; case D_RIGHT : *x += dy; *y += dx; break; } } void DrawPinIOMark(GWire *w,int d,int iod,int atype) { int x,y; Icon *arrow; GC gc; if (atype == IODT_PORT) gc = TkGate.modportGC; else gc = TkGate.instGC; GetPinIOMark(w,d,iod,atype,&x,&y,&arrow); Icon_draw(TkGate.D,TkGate.W,gc,ctow_x(x),ctow_y(y),arrow); }