/**************************************************************************** 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 #include #include #include #include "gsim.h" #include "ycmalloc.h" int loops_detected = 0; //#define PORT_ISCUT(P) ((P->p_type->flags & PF_CUT) || (P->p_gate->g_flags & GF_CPCUT)) int PORT_ISCUT(SPort *P) { int c1 = (P->p_type->flags & PF_CUT); int c2 = (P->p_gate->g_flags & GF_CPCUT); if (c2) printf("gate cut\n"); return c1 || c2; } void uninit_CPath(List *L) { ListElem *E; for (E = List_first(L);E;E = List_next(L,E)) { CPathHop *ph = (CPathHop*) ListElem_obj(E); free(ph); } List_uninit(L); } CPathHop *new_CPathHop(SPort *f,SNet *n,SPort *t) { CPathHop *h = (CPathHop*) malloc(sizeof(CPathHop)); h->from = f; h->net = n; h->to = t; return h; } CPathHop *copy_CPathHop(CPathHop *ph) { CPathHop *h = (CPathHop*) malloc(sizeof(CPathHop)); *h = *ph; return h; } /* * Return non-zero if any ports opposite to P are marked with * the loop flag (e.g., if P is an adder input, then it will * return non-zero if either the sum output or carry output * are marked). */ int cpath_anyLPCheck(SPort *P) { SGate *g = P->p_gate; int j; for (j = 0; j < g->g_ports.num;j++) { SPort *P2 = g->g_ports.port[j]; simTime d = g->g_type->gi_delay ? (*g->g_type->gi_delay)(P,P2) : NO_TIME; SNet *n = g->g_ports.port[j]->p_net; n = SNet_canonical(n); if (d == NO_TIME) continue; if ((n->n_flags & NF_LPCHECK)) return 1; } return 0; } void SNet_propBackDelay(SNet *n,simTime t) { int i; n = SNet_canonical(n); if ((n->n_flags & NF_LPCHECK)) { sendMsg("cpath_loop %s",n->n_name); loops_detected = 1; return; } if (t <= n->n_backDelay) return; n->n_backDelay = t; n->n_flags |= NF_LPCHECK; for (i = 0;i < n->n_ports.num; i++) { SPort *P = n->n_ports.port[i]; SGate *g = P->p_gate; SGateInfo *gi = g->g_type; if (SPort_effectiveType(P) != GIO_OUT || PORT_ISCUT(P)) continue; if (gi->gi_propBackDelay) (*gi->gi_propBackDelay)(P,t); } n->n_flags &= ~NF_LPCHECK; } void SNet_propFrwdDelay(SNet *n,simTime t) { int i; n = SNet_canonical(n); if ((n->n_flags & NF_LPCHECK)) { sendMsg("cpath_loop %s",n->n_name); loops_detected = 1; return; } if (t <= n->n_frwdDelay) return; n->n_frwdDelay = t; n->n_flags |= NF_LPCHECK; for (i = 0;i < n->n_ports.num; i++) { SPort *P = n->n_ports.port[i]; SGate *g = P->p_gate; SGateInfo *gi = g->g_type; if (SPort_effectiveType(P) != GIO_IN || PORT_ISCUT(P)) continue; if (gi->gi_propFrwdDelay) (*gi->gi_propFrwdDelay)(P,t); } n->n_flags &= ~NF_LPCHECK; } void cpath_clearDPathMark(EvQueue *Q) { HashElem *E; for (E = Hash_first(&Q->mod->m_nets);E; E = Hash_next(&Q->mod->m_nets,E)) { SNet *n = (SNet*) HashElem_obj(E); n->n_flags &= ~NF_DPATH; } } void clearDelays(EvQueue *Q) { HashElem *E; int i; for (E = Hash_first(&Q->mod->m_gates);E; E = Hash_next(&Q->mod->m_gates,E)) { SGate *g = (SGate*) HashElem_obj(E); for (i = 0;i < g->g_ports.num;i++) { SPort *P = g->g_ports.port[i]; P->p_frwdDelay = -1; P->p_backDelay = -1; } } for (E = Hash_first(&Q->mod->m_nets);E; E = Hash_next(&Q->mod->m_nets,E)) { SNet *n = (SNet*) HashElem_obj(E); n->n_frwdDelay = -1; n->n_backDelay = -1; } } void propForward(EvQueue *Q) { HashElem *E; int i; for (E = Hash_first(&Q->mod->m_gates);E; E = Hash_next(&Q->mod->m_gates,E)) { SGate *g = (SGate*) HashElem_obj(E); SGateInfo *gi = g->g_type; for (i = 0;i < g->g_ports.num;i++) { SPort *P = g->g_ports.port[i]; if (SPort_effectiveType(P) == GIO_OUT && PORT_ISCUT(P)) { P->p_frwdDelay = gi->gi_delay ? (*gi->gi_delay)(P,0) : 0; SNet_propFrwdDelay(P->p_net,P->p_frwdDelay); } } } } void propBackward(EvQueue *Q) { HashElem *E; int i; /* First prop back from input gates with PF_CUT mark */ for (E = Hash_first(&Q->mod->m_gates);E; E = Hash_next(&Q->mod->m_gates,E)) { SGate *g = (SGate*) HashElem_obj(E); SGateInfo *gi = g->g_type; for (i = 0;i < g->g_ports.num;i++) { SPort *P = g->g_ports.port[i]; if (SPort_effectiveType(P) == GIO_IN && PORT_ISCUT(P)) { P->p_backDelay = gi->gi_delay ? (*gi->gi_delay)(P,0) : 0; SNet_propBackDelay(P->p_net,P->p_backDelay); } } } /* * Propogate back from any nets with no input ports attacheted to them */ for (E = Hash_first(&Q->mod->m_nets);E; E = Hash_next(&Q->mod->m_nets,E)) { SNet *n = (SNet*) HashElem_obj(E); int has_in = 0; for (i = 0;i < n->n_ports.num;i++) { SPort *P = n->n_ports.port[i]; if (SPort_effectiveType(P) == GIO_IN) has_in = 1; } if (!has_in) SNet_propBackDelay(n,0); } /* * Propogate back from remaining nets */ for (E = Hash_first(&Q->mod->m_nets);E; E = Hash_next(&Q->mod->m_nets,E)) { SNet *n = (SNet*) HashElem_obj(E); SNet_propBackDelay(n,0); } } static int net_delay_compare(const void *vA,const void *vB) { SNet *A = *(SNet**)vA; SNet *B = *(SNet**)vB; simTime ad = A->n_frwdDelay + A->n_backDelay; simTime bd = B->n_frwdDelay + B->n_backDelay; return bd-ad; } SNet **getDList(EvQueue *Q,int *d_len) { SNet **d_list; /* Vector of nets in reverse delay order */ HashElem *E; int i; *d_len = Hash_numElems(&Q->mod->m_nets); d_list = (SNet**) malloc(sizeof(SNet*) * (*d_len + 1)); i = 0; for (E = Hash_first(&Q->mod->m_nets);E; E = Hash_next(&Q->mod->m_nets,E)) { SNet *n = (SNet*) HashElem_obj(E); if (n != SNet_canonical(n)) continue; // if (!n->n_source) d_list[i++] = n; } *d_len = i; d_list[i++] = 0; if (*d_len > 1) qsort(d_list,*d_len,sizeof(SNet*),net_delay_compare); return d_list; } /* * Starting at net N, add nets to the end of list L to * form the longest path to an output. A unique path will * be selected for each value of pidx. If pidx is higher than * the number of paths through N, then -1 is returned. */ int makeForwardPath(List *L,SNet *N,unsigned pidx) { simTime maxDelay = NO_TIME; List nextNodes; CPathHop *cp,*end_cp; int num,sel; int i,j; int r_value; int any_next; #if 0 sendMsg("echo makeForwardPath(%s, %d) flags=%x\n",N->n_name,pidx,N->n_flags); #endif /* * If the loop flag is set, count this is the end of a path. */ if ((N->n_flags & NF_LPCHECK)) { if (pidx == 0) return 0; else { return -1; } } N->n_flags |= NF_LPCHECK; List_init(&nextNodes); any_next = 0; for (i = 0;i < N->n_ports.num; i++) { SPort *P = N->n_ports.port[i]; if (SPort_effectiveType(P) == GIO_IN && !PORT_ISCUT(P)) { SGate *g = P->p_gate; if (cpath_anyLPCheck(P)) { continue; } for (j = 0; j < g->g_ports.num;j++) { SPort *P2 = g->g_ports.port[j]; simTime d = g->g_type->gi_delay ? (*g->g_type->gi_delay)(P,P2) : NO_TIME; SNet *n = g->g_ports.port[j]->p_net; n = SNet_canonical(n); if (d == NO_TIME) continue; any_next = 1; d += n->n_backDelay; if (d > maxDelay) { List_flush(&nextNodes); maxDelay = d; } if ((n->n_flags & NF_DPATH)) continue; if (d == maxDelay) { List_addToTail(&nextNodes,new_CPathHop(P,n,g->g_ports.port[j])); } } } } num = List_numElems(&nextNodes); if (num <= 0) { uninit_CPath(&nextNodes); N->n_flags &= ~NF_LPCHECK; if (pidx == 0 && !any_next) { return 0; } else { return -1; } } sel = pidx % num; pidx /= num; cp = List_nth(&nextNodes,sel); end_cp = (CPathHop*) ListElem_obj(List_last(L)); end_cp->to = cp->from; List_addToTail(L,new_CPathHop(cp->to,cp->net,0)); r_value = makeForwardPath(L,cp->net,pidx); uninit_CPath(&nextNodes); N->n_flags &= ~NF_LPCHECK; return r_value; } int makeBackwardPath(List *L,SNet *N,unsigned pidx) { simTime maxDelay = NO_TIME; List nextNodes; CPathHop *cp,*end_cp; int num,sel,r_value; int i,j; int any_next; /* * If the loop flag is set, count this is the end of a path. */ if ((N->n_flags & NF_LPCHECK)) { if (pidx == 0) return 0; else { return -1; } } N->n_flags |= NF_LPCHECK; List_init(&nextNodes); any_next = 0; for (i = 0;i < N->n_ports.num; i++) { SPort *P = N->n_ports.port[i]; if (SPort_effectiveType(P) == GIO_OUT && !PORT_ISCUT(P)) { SGate *g = P->p_gate; if (cpath_anyLPCheck(P)) { continue; } for (j = 0; j < g->g_ports.num;j++) { SPort *P2 = g->g_ports.port[j]; simTime d = g->g_type->gi_delay ? (*g->g_type->gi_delay)(P,P2) : NO_TIME; SNet *n = g->g_ports.port[j]->p_net; n = SNet_canonical(n); if (d == NO_TIME || (n->n_flags & NF_LPCHECK)) continue; any_next = 1; d += n->n_frwdDelay; if (d > maxDelay) { List_flush(&nextNodes); maxDelay = d; } if ((n->n_flags & NF_DPATH)) continue; if (d == maxDelay) { List_addToTail(&nextNodes,new_CPathHop(P,n,P2)); } } } } num = List_numElems(&nextNodes); if (num <= 0) { N->n_flags &= ~NF_LPCHECK; uninit_CPath(&nextNodes); if (pidx == 0 && !any_next) return 0; else { return -1; } } sel = pidx % num; pidx /= num; cp = List_nth(&nextNodes,sel); end_cp = (CPathHop*) ListElem_obj(List_first(L)); end_cp->from = cp->from; List_addToHead(L,new_CPathHop(0,cp->net,cp->to)); r_value = makeBackwardPath(L,cp->net,pidx); uninit_CPath(&nextNodes); N->n_flags &= ~NF_LPCHECK; return r_value; } /* Flag a net as "done" with respect to delay calculations and propegate the "done" property. */ void cpath_flagDoneNet(SNet *n) { int i,j; n = SNet_canonical(n); if ((n->n_flags & NF_DPATH)) return; n->n_flags |= NF_DPATH; for (i = 0;i < n->n_ports.num; i++) { SPort *P = n->n_ports.port[i]; SGate *g = P->p_gate; int p_type = SPort_effectiveType(P); for (j = 0; j < g->g_ports.num;j++) { SPort *P2 = g->g_ports.port[j]; if (SPort_effectiveType(P2) == p_type && !(P2->p_net->n_flags & NF_DPATH)) break; } if (j != g->g_ports.num) continue; /* There was an unmarked net */ for (j = 0; j < g->g_ports.num;j++) { SPort *P2 = g->g_ports.port[j]; if (SPort_effectiveType(P2) != p_type) cpath_flagDoneNet(P2->p_net); } } } void chooseEndPorts(List *L) { CPathHop *first_cp,*last_cp; int i; first_cp = (CPathHop*) ListElem_obj(List_first(L)); last_cp = (CPathHop*) ListElem_obj(List_last(L)); for (i = 0;i < last_cp->net->n_ports.num; i++) { SPort *P = last_cp->net->n_ports.port[i]; if (SPort_effectiveType(P) != GIO_IN) continue; last_cp->to = P; } for (i = 0;i < first_cp->net->n_ports.num; i++) { SPort *P = first_cp->net->n_ports.port[i]; if (SPort_effectiveType(P) != GIO_OUT) continue; first_cp->from = P; } } void makePathString(char *q,List *L) { ListElem *E; *q = 0; for (E = List_first(L);E;E = List_next(L,E)) { CPathHop *ph = (CPathHop*) ListElem_obj(E); SNet *pn = ph->net; q += sprintf(q," "); if (ph->from) { q += sprintf(q,"{<%s[%s]>",ph->from->p_gate->g_name,ph->from->p_name); } else q += sprintf(q,"{<>"); q += sprintf(q,":%s:",pn->n_name); if (ph->to) { q += sprintf(q,"<%s[%s]>}",ph->to->p_gate->g_name,ph->to->p_name); } else q += sprintf(q,"<>}"); } } void cpath_LPCheck_mark(List *L,int markp) { ListElem *E; for (E = List_first(L);E;E = List_next(L,E)) { CPathHop *ph = (CPathHop*) ListElem_obj(E); SNet *n = ph->net; if (markp) n->n_flags |= NF_LPCHECK; else n->n_flags &= ~NF_LPCHECK; } } void reportCriticalPaths(EvQueue *Q,SNet **d_list,int max_path) { int i,j,k,l; simTime cur_t = NO_TIME; #if 0 sendMsg("echo reportCriticalPaths: %d",max_path); #endif for (i = 0;d_list[i];i++) { SNet *n = d_list[i]; simTime t = n->n_frwdDelay + n->n_backDelay; if (t != cur_t) { cpath_clearDPathMark(Q); cur_t = t; } l = 0; k = 0; for (j = 0;;j++, l++) { List L; char buf[STRMAX]; List_init(&L); List_addToTail(&L,new_CPathHop(0,n,0)); if (makeForwardPath(&L,n,j) == -1) { int xx; k++; j = 0; List_flush(&L); List_addToTail(&L,new_CPathHop(0,n,0)); xx = makeForwardPath(&L,n,j); } cpath_LPCheck_mark(&L,1); n->n_flags &= ~NF_LPCHECK; if (makeBackwardPath(&L,n,k) == -1) { break; } cpath_LPCheck_mark(&L,0); #if 0 sendMsg("echo %s (%d,%d) --- frwd:%d back:%d",n->n_name,j,k,n->n_frwdDelay,n->n_backDelay); #endif chooseEndPorts(&L); makePathString(buf,&L); #if 0 sendMsg("echo %d: [%d %d %s] %s",l,n->n_frwdDelay,n->n_backDelay,n->n_name,buf); #endif sendMsg("cpath %d %s",n->n_frwdDelay+n->n_backDelay,buf); uninit_CPath(&L); if (--max_path <= 0) { cpath_flagDoneNet(n); return; } } cpath_flagDoneNet(n); } } void cpath_reportNetDelays(EvQueue *Q) { HashElem *E; for (E = Hash_first(&Q->mod->m_nets);E; E = Hash_next(&Q->mod->m_nets,E)) { SNet *n = (SNet*) HashElem_obj(E); SNet *cn = SNet_canonical(n); sendMsg("netdelay %s %d %d",n->n_name,cn->n_frwdDelay, cn->n_backDelay); if (n != cn) sendMsg("netalias %s %s",n->n_name,cn->n_name); } } void findCriticalPaths(EvQueue *Q,int n) { SNet **d_list; /* Vector of nets in reverse delay order */ int d_len; loops_detected = 0; clearDelays(Q); propForward(Q); propBackward(Q); if (!loops_detected) { d_list = getDList(Q,&d_len); reportCriticalPaths(Q,d_list,n); free(d_list); cpath_reportNetDelays(Q); } sendMsg("cdone"); }