/**************************************************************************** Copyright (C) 1987-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************/ #include #include #include #include #include "hash.h" #include "gsim.h" #define PORTLIST_STEP 8 extern SHash module_table; void Concat_setDirections(SModule *M); void setGateDelayParms(SGate*); SModule *new_SModule(const char *name) { SModule *M = (SModule*) malloc(sizeof(SModule)); M->m_name = strdup(name); SPortList_init(&M->m_ports); SHash_init(&M->m_nets); SHash_init(&M->m_gates); return M; } void SModule_addPort(SModule *M,SNet *N) { SPortList_add(&M->m_ports,new_SPort(N->n_name,N,0)); } SNet *SModule_findAddNet(SModule *M,const char *net) { SNet *N = (SNet*)SHash_find(&M->m_nets,net); if (!N) { N = new_SNet(net,1); SHash_insert(&M->m_nets,N->n_name,N); } return N; } SNet *SModule_findNet(SModule *M,const char *net) { SNet *N = (SNet*)SHash_find(&M->m_nets,net); return N; } SGate *SModule_findGate(SModule *M,const char *gat) { SGate *G = (SGate*)SHash_find(&M->m_gates,gat); return G; } void SModule_addGate(SModule *M,SGate *g) { SHash_insert(&M->m_gates,g->g_name,g); } static void SModule_printNets(SModule *M,FILE *f) { HashElem *E; int C; C = 0; for (E = Hash_first(&M->m_nets);E;E = Hash_next(&M->m_nets,E)) { SNet *N = (SNet*) HashElem_obj(E); if (C && (C + strlen(N->n_name) > 75)) { fprintf(f,";\n"); C = 0; } if (C == 0) { fprintf(f,"wire "); C += 5; } else { fprintf(f,", "); C += 2; } if (N->n_merge) fprintf(f,"(%s)",N->n_name); else fprintf(f,"%s",N->n_name); C += strlen(N->n_name); } if (C != 0) fprintf(f,";\n"); fprintf(f,"\n"); } static void SModule_printGates(SModule *M,FILE *f) { HashElem *E; for (E = Hash_first(&M->m_gates);E;E = Hash_next(&M->m_gates,E)) { SGate *g = (SGate*) HashElem_obj(E); SGate_print(g,f); } fprintf(f,"\n"); } void SModule_print(SModule *M,FILE *f) { fprintf(f,"module %s",M->m_name); if (M->m_ports.num > 0) { int i; fprintf(f,"("); for (i = 0;i < M->m_ports.num;i++) { if (i != 0) fprintf(f,", "); fprintf(f,"%s",M->m_ports.port[i]->p_name); } fprintf(f,")"); } fprintf(f,";\n"); SModule_printNets(M,f); SModule_printGates(M,f); fprintf(f,"endmodule\n\n"); } void SModule_mergeNets(SModule *M,SNet *N,SNet *SN) { SN->n_merge = N; } /* Helping function to marge nets at module boundaries. */ static void SModule_attachPorts(SModule *M,const char *root_name,SGate *g,SHash *netTable,SHash *portTable) { int i; for (i = 0;i < g->g_ports.num;i++) { SPort *P = g->g_ports.port[i]; SNet *N,*SN; if (netTable) { N = (SNet*) SHash_find(netTable,P->p_net->n_name); assert(N); } else N = P->p_net; SN = (SNet*) SHash_find(portTable,P->p_name); if (SN) { if (N->n_nbits != SN->n_nbits) { char buf[STRMAX]; if (SGate_isErrMarked(g)) continue; if (*root_name) sprintf(buf,"%s.%s",root_name,g->g_name); else strcpy(buf,g->g_name); errorGate(buf,"Expected bit width of %d for port '%s'.",SN->n_nbits,P->p_name); SGate_errMark(g); } SModule_mergeNets(M,N,SN); } else { char buf[STRMAX]; if (SGate_isErrMarked(g)) continue; if (*root_name) sprintf(buf,"%s.%s",root_name,g->g_name); else strcpy(buf,g->g_name); errorGate(buf,"Pin '%s' on module is not defined.",P->p_name); SGate_errMark(g); } } } void SModule_expandSubMod(SModule *M,SModule *SM,SGate *g,const char *root_name,SHash *portTable) { char buf[STRMAX]; HashElem *E; int i; SHash netTable; SHash_init(&netTable); /* For each net in submodule SM, create a net in the expand module by appending the net name in SM to the root name. */ for (E = Hash_first(&SM->m_nets);E;E = Hash_next(&SM->m_nets,E)) { SNet *sN = (SNet*) HashElem_obj(E); SNet *N; sprintf(buf,"%s.%s",root_name,sN->n_name); N = SModule_findAddNet(M,buf); N->n_source = sN; N->n_nbits = sN->n_nbits; SHash_insert(&netTable,sN->n_name,N); } /* Create the port table for SM. The port table maps port names to nets in the current instance of SM. */ for (i = 0;i < SM->m_ports.num;i++) { SPort *P = SM->m_ports.port[i]; SNet *N; sprintf(buf,"%s.%s",root_name,P->p_name); N = SModule_findAddNet(M,buf); SHash_insert(portTable,P->p_name,N); } /* For each gate submodule SM, create a gate in the expand module by appending the gate name in SM to the root name. Attach wires in the new gate to the corresponding new nets. */ for (E = Hash_first(&SM->m_gates);E;E = Hash_next(&SM->m_gates,E)) { SGate *sg = (SGate*) HashElem_obj(E); SGateInfo *gi = sg->g_type; sprintf(buf,"%s.%s",root_name,sg->g_name); if (gi) { /* This is a regular gate. */ SGate *ng = (*sg->g_type->gi_copyGate)(sg,buf,M); for (i = 0;i < sg->g_ports.num;i++) { SNet *N; N = (SNet*) SHash_find(&netTable,sg->g_ports.port[i]->p_net->n_name); SGate_addPort(ng,sg->g_ports.port[i]->p_name,N ,sg->g_ports.port[i]->p_comp); } } else { /* This is a submodule. */ SModule *ssM = (SModule*) SHash_find(&module_table,sg->g_typeName); SHash portTable; SHash_init(&portTable); if (!ssM) { errorGate(sg->g_name,"Called module '%s' undefined.",sg->g_typeName); continue; } SModule_expandSubMod(M,ssM,sg,buf,&portTable); SModule_attachPorts(M,root_name,sg,&netTable,&portTable); SHash_uninit(&portTable); } } SHash_uninit(&netTable); } /* Expand sub-modules in top-level module M to create a single flat module. */ void SModule_expand(SModule *M) { HashElem *E; SHash mod_set; /* Set of expanded modules */ SHash_init(&mod_set); for (E = Hash_first(&M->m_gates);E;E = Hash_next(&M->m_gates,E)) { SGate *g = (SGate*) HashElem_obj(E); SModule *SM; if (g->g_type) continue; SM = (SModule*) SHash_find(&module_table,g->g_typeName); if (!SM) { errorGate(g->g_name,"Called module '%s' undefined.",g->g_typeName); continue; } SHash_insert(&mod_set,g->g_name,g); } for (E = Hash_first(&mod_set);E;E = Hash_next(&mod_set,E)) { SGate *g = (SGate*) HashElem_obj(E); SModule *SM; SHash portTable; SM = (SModule*) SHash_find(&module_table,g->g_typeName); SHash_init(&portTable); SModule_expandSubMod(M,SM,g,g->g_name,&portTable); SModule_attachPorts(M,"",g,0,&portTable); SHash_uninit(&portTable); } for (E = Hash_first(&mod_set);E;E = Hash_next(&mod_set,E)) { SGate *g = (SGate*) HashElem_obj(E); SHash_remove(&M->m_gates,g->g_name); } SHash_uninit(&mod_set); } void SModule_finalize(SModule *M) { HashElem *E; for (E = Hash_first(&M->m_gates);E;E = Hash_next(&M->m_gates,E)) { SGate *g = (SGate*) HashElem_obj(E); SGate_finalize(g); } for (E = Hash_first(&M->m_nets);E;E = Hash_next(&M->m_nets,E)) { SNet *N = (SNet*) HashElem_obj(E); SState_init(&N->n_state,N->n_nbits); SState_init(&N->n_oldState,N->n_nbits); SState_unknown(&N->n_state); SState_unknown(&N->n_oldState); } Concat_setDirections(M); } SGate *new_SGate(const char *gtype,const char *gname) { SGate *g = (SGate*)malloc(sizeof(SGate)); g->g_type = 0; g->g_typeName = strdup(gtype); g->g_name = strdup(gname); g->g_flags = 0; g->g_source = 0; SPortList_init(&g->g_ports); g->g_data = 0; g->g_delayParms = 0; g->g_area = 0; g->g_staticPower = 0; g->g_tech = strdup("default"); return g; } void SGate_addPort(SGate *g,const char *pname,SNet *N,int comp) { if (!pname && g->g_type) { SGateInfo *gi = g->g_type; int i = g->g_ports.num; if (i >= gi->gi_numPads) i = gi->gi_numPads-1; pname = g->g_type->gi_pad[i].name; } SPortList_add(&g->g_ports,new_SPort(pname,N,comp)); #if 0 #define XXX(p) ((p) ? (p)->p_net->n_name : "-") sendMsg("echo ATTACH(%p) Z=%s I=%s G=%s\n",g, XXX(g->g_ports.port[0]), XXX(g->g_ports.port[1]), XXX(g->g_ports.port[2])); #endif } static SGateInfo *gpc_type = 0; static int gate_port_compare(const void *vA,const void *vB) { SPort *A = *(SPort**)vA; SPort *B = *(SPort**)vB; return SGateInfo_portRank(gpc_type,A->p_name) - SGateInfo_portRank(gpc_type,B->p_name); } void SGate_sortPins(SGate *g) { gpc_type = g->g_type; qsort(g->g_ports.port,g->g_ports.num,sizeof(SPort*),gate_port_compare); } void SGate_finalize(SGate *g) { int i; NHash nets; NHash_init(&nets); for (i = 0;i < g->g_ports.num;i++) { SPort *P = g->g_ports.port[i]; P->p_net = SNet_canonical(P->p_net); P->p_gate = g; P->p_gpos = i; P->p_isDup = 0; if (g->g_type) { if (i < g->g_type->gi_numPads) P->p_type = &g->g_type->gi_pad[i]; else P->p_type = &g->g_type->gi_pad[g->g_type->gi_numPads-1]; SNet_attachPort(P->p_net,P); } if (NHash_find(&nets,(nkey_t)P->p_net)) P->p_isDup = 1; else NHash_insert(&nets,(nkey_t)P->p_net,P->p_net); SState_init(&P->p_state,P->p_net->n_nbits); SState_unknown(&P->p_state); SState_init(&P->p_qstate,P->p_net->n_nbits); SState_unknown(&P->p_qstate); } NHash_uninit(&nets); setGateDelayParms(g); } void SGate_print(SGate *g,FILE *f) { int i; fprintf(f," %s %s (",g->g_typeName,g->g_name); for (i = 0;i < g->g_ports.num;i++) { SPort *P = g->g_ports.port[i]; if (i != 0) fprintf(f,", "); fprintf(f,".%s(%s)",P->p_name,P->p_net->n_name); } fprintf(f,");\n"); } void SGate_errMark(SGate *g) { if (g->g_source) g = g->g_source; g->g_flags |= GF_ERRREP; } int SGate_isErrMarked(SGate *g) { if (g->g_source) g = g->g_source; return (g->g_flags & GF_ERRREP) != 0; } SState *SGate_allocPortState(SGate *g,int p) { SState *pS = &g->g_ports.port[p]->p_net->n_state; SState *cS = alloc_SState(); SState_reinit(cS,pS->nbits); SState_copy(cS,pS); if (g->g_ports.port[p]->p_comp) SState_not(cS,cS); return cS; } SPort *new_SPort(const char *name,SNet *N,int comp) { SPort *P = (SPort*)malloc(sizeof(SPort)); P->p_name = name ? strdup(name) : 0; P->p_comp = comp; P->p_net = N; P->p_gate = 0; P->p_gpos = -1; P->p_nedge = NO_TIME; P->p_ledge = NO_TIME; P->p_dynamicPower = 0; return P; } SNet *new_SNet(const char *name,int nbits) { SNet *N = (SNet*)malloc(sizeof(SNet)); N->n_name = strdup(name); N->n_nbits = nbits; N->n_flags = 0; N->n_merge = 0; N->n_watchNames = 0; N->n_breaks = 0; N->n_source = 0; SPortList_init(&N->n_ports); return N; } void SNet_setNBits(SNet *N,int nbits) { N->n_nbits = nbits; } void SNet_attachPort(SNet *N,SPort *P) { int i; for (i = 0;i < N->n_ports.num;i++) if (N->n_ports.port[i] == P) return; SPortList_add(&N->n_ports,P); } SNet *SNet_canonical(SNet *n) { while (n->n_merge) n = n->n_merge; return n; } void SNet_errMark(SNet *n) { if (n->n_source) n = n->n_source; n->n_flags |= NF_ERRREP; } int SNet_isErrMarked(SNet *n) { if (n->n_source) n = n->n_source; return (n->n_flags & NF_ERRREP) != 0; } void SPortList_init(SPortList *L) { L->num = 0; L->port = 0; } void SPortList_add(SPortList *L,SPort *P) { if ((L->num % PORTLIST_STEP) == 0) { SPort **pl = (SPort**) calloc(L->num+PORTLIST_STEP,sizeof(SPort*)); if (L->port) { int i; for (i = 0;i < L->num;i++) pl[i] = L->port[i]; free(L->port); } L->port = pl; } L->port[L->num++] = P; } /* Return the effective type for an INOUT port on a concat gate */ int SPort_effectiveTypeAux(SPort *P) { switch (P->p_type->io) { case GIO_WIRE : return Concat_effectivePortType(P); case GIO_TRI : return GIO_OUT; } return P->p_type->io; } void SModule_check(SModule *M) { HashElem *E; for (E = Hash_first(&M->m_gates);E;E = Hash_next(&M->m_gates,E)) { SGate *g = (SGate*) HashElem_obj(E); if (g->g_type && !SGate_isErrMarked(g)) if ((g->g_type->gi_checkGate)(g)) SGate_errMark(g); } for (E = Hash_first(&M->m_nets);E;E = Hash_next(&M->m_nets,E)) { SNet *n = (SNet*) HashElem_obj(E); int i,nout,ntri,nio,nw; if (n->n_merge || SNet_isErrMarked(n)) continue; SNet_errMark(n); nout = ntri = nio = nw = 0; for (i = 0;i < n->n_ports.num;i++) { SPort *P = n->n_ports.port[i]; switch (P->p_type->io) { case GIO_OUT : nout++; break; case GIO_TRI : ntri++; break; case GIO_INOUT : nio++; break; case GIO_WIRE : nw++; break; } } if (nout + ntri + nio + nw == 0) errorNet(n->n_name,"No gates driving net '%s'.",n->n_name); else if (nout > 1) errorNet(n->n_name,"More than one non-tristate gate driving net '%s'.",n->n_name); else if (ntri != 0 && nout != 0) errorNet(n->n_name,"Net '%s' has mixed tristate and non-tristate drivers.",n->n_name); } } void SModule_init(SModule *M,EvQueue *Q) { HashElem *E; for (E = Hash_first(&M->m_gates);E;E = Hash_next(&M->m_gates,E)) { SGate *g = (SGate*) HashElem_obj(E); if (g->g_type && g->g_type->gi_initGate) (g->g_type->gi_initGate)(Q,g); } }