/**************************************************************************** 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 "gsim.h" #include "memory.h" void init_process(); void init_and(); void init_or(); void init_xor(); void init_buf(); void init_switch(); void init_supply(); void init_bufif(); void init_nmos(); void init_pmos(); void init_add(); void init_clock(); void init_register(); void init_flipflop(); void init_mux(); void init_demux(); void init_concat(); void init_mult(); void init_div(); void init_ram(); void init_rom(); void init_lshift(); void init_rshift(); void init_arshift(); void init_roll(); void init_tty(); void init_tap(); void init_led(); static SHash gate_types; static SGateInfo ignore = { GT_IGNORE, "ignored" }; static char *ignored_types[] = { "input","output","inout","joint", "comment", "frame" }; static unsigned spread(unsigned M,unsigned x) { unsigned R = 0; int i,j; j = 0; for (i = 0;i < 32;i++) if ((M & (1 << i)) && (x & (1 << j++))) R |= (1 << i); return R; } /* * Register new gate types and do some pre-processing. */ void SGateInfo_register(SGateInfo *gi,const char *name) { static int code = GT_IGNORE+1; int i; if (gi->gi_code <= 0) gi->gi_code = code++; if (name) SHash_insert(&gate_types,name,gi); else { char buf[STRMAX],*T; strcpy(buf,gi->gi_name); for (T = strtok(buf,":");T;T = strtok(0,":")) SHash_insert(&gate_types,T,gi); } /* * Initialize pad numbers */ for (i = 0;i < gi->gi_numPads;i++) gi->gi_pad[i].idx = i; } int gate_properties_lookup(const char *func,const char *name,void *data,int *rval) { SGate *g = (SGate*) data; int l = strlen(name); int b = 0, n = 0, c = 0; int i; if (!func) return EE_BADFUNC; if (!name) return EE_NOTDEF; for (i = 0;i < g->g_ports.num;i++) { SPort *P = g->g_ports.port[i]; if (strncmp(P->p_name,name,l) == 0 && (!P->p_name[l] || isdigit(P->p_name[l]))) { if (P->p_net->n_nbits > b) b = P->p_net->n_nbits; if (P->p_comp) c++; n++; } } if (n == 0) { expr_errsym = name; return EE_NOTDEF; } if (strcmp(func,"bits") == 0) { *rval = b; return 0; } else if (strcmp(func,"inv") == 0) { *rval = c; return 0; } else if (strcmp(func,"num") == 0) { *rval = n; return 0; } else { expr_errsym = func; return EE_BADFUNC; } return 0; } void delayErrorMessage(int rr,SGate *g,const char *dname) { switch (rr) { case EE_NOTDEF : errorGate(g->g_name,"Undefined literal '%s' in %s<%s> gate delay expression (check parameters file)", expr_errsym,g->g_typeName,dname); break; case EE_BADFUNC : errorGate(g->g_name,"Illegal function name '%s' in %s<%s> gate delay expression (check parameters file)", expr_errsym,g->g_typeName,dname); break; case EE_DIV0 : errorGate(g->g_name,"Division by zero computing %s<%s> gate delay (check parameters file)", g->g_typeName,dname); break; default : errorGate(g->g_name,"Can not evaluate (code %d) on %s<%s> gate delay expression (check parameters file)", rr,g->g_typeName,dname); break; } } void areaPowerErrorMessage(int rr,SGate *g,const char *what) { switch (rr) { case EE_NOTDEF : errorGate(g->g_name,"Undefined literal '%s' in %s gate %s expression (check parameters file)", expr_errsym,g->g_typeName,what); break; case EE_BADFUNC : errorGate(g->g_name,"Illegal function name '%s' in %s gate %s expression (check parameters file)", expr_errsym,g->g_typeName,what); break; case EE_DIV0 : errorGate(g->g_name,"Division by zero computing %s gate %s (check parameters file)", g->g_typeName,what); break; default : errorGate(g->g_name,"Can not evaluate (code %d) on %s gate %s expression (check parameters file)", rr,g->g_typeName,what); break; } } /* Set the delay (also area and power) parameters for a gate. */ void setGateDelayParms(SGate *g) { SGateInfo *gi = g->g_type; GDelayDef *dd; int i,j,n; int rr; char buf[STRMAX],*p; if (!gi) return; strcpy(buf,gi->gi_name); p = strchr(buf,':'); if (p) *p = 0; dd = GDelayDef_find(g->g_tech,buf); if (!dd) { /* Missing delay definition is an error if the gate has at least one error parameter. */ if (gi->gi_delayNames[0].ds_name) errorGate(g->g_name,"No delay parameters specified."); return; } if (dd) { if (!(rr = Expr_eval(dd->dd_area,&n,gate_properties_lookup,g))) { g->g_area = n; if (n < 0) errorGate(g->g_name,"Area %d on '%s' gate is negative (check parameters file)",n,g->g_typeName); total_area += n; } else areaPowerErrorMessage(rr,g,"area"); if (!(rr = Expr_eval(dd->dd_power,&n,gate_properties_lookup,g))) { g->g_staticPower = n; total_staticPower += n; if (n < 0) errorGate(g->g_name,"Power %d on '%s' gate is negative (check parameters file)",n,g->g_typeName); } else areaPowerErrorMessage(rr,g,"power"); } /* * Set delay parameters based on technology if not already set as custom delay. */ if (!g->g_delayParms) { /* Compute the length of and allocate the gate delay array. */ n = 0; for (i = 0;gi->gi_delayNames[i].ds_name;i++) n++; if (n == 0) n = 1; g->g_delayParms = (int*) malloc(sizeof(int)*n); /* Initialize all delays to '1' in case we fail to find a real delay value */ for (i = 0;gi->gi_delayNames[i].ds_name;i++) { g->g_delayParms[i] = 1; } for (i = 0;gi->gi_delayNames[i].ds_name;i++) { int delay = 1; for (j = 0;j < dd->dd_numDelays;j++) if (strcmp(gi->gi_delayNames[i].ds_name,dd->dd_names[j]) == 0) break; if (j >= dd->dd_numDelays) { for (j = 0;j < dd->dd_numDelays;j++) if (strcmp(dd->dd_names[j],"*") == 0) break; } if (j >= dd->dd_numDelays) { errorGate(g->g_name,"Can't find %s<%s> delay value (check parameters file)", g->g_typeName,gi->gi_delayNames[i].ds_name); continue; } rr = Expr_eval(dd->dd_delay[i],&delay,gate_properties_lookup,g); if (rr) { delayErrorMessage(rr,g,gi->gi_delayNames[i].ds_name); continue; } g->g_delayParms[i] = delay; } } /* Go through delays again to check for bogus values */ for (i = 0;gi->gi_delayNames[i].ds_name;i++) { int delay = g->g_delayParms[i]; if (delay <= 0) { errorGate(g->g_name,"Delay on %s<%s> is non-positive (check parameters file)", g->g_typeName,gi->gi_delayNames[i]); delay = 1; } if (delay >= THYMEWHEEL_SIZE) { errorGate(g->g_name,"Delay of %d on %s<%s> is too large (check parameters file)", delay,g->g_typeName,gi->gi_delayNames[i]); delay = 1; } g->g_delayParms[i] = delay; #if 0 logMsg("delay %s<%s> on %s is %d (tech=%s : %s)",g->g_typeName,gi->gi_delayNames[i],g->g_name,delay,g->g_tech,dd->dd_tech); #endif } } SGateInfo *SGateInfo_find(const char *name) { return (SGateInfo*) SHash_find(&gate_types,name); } unsigned SGateInfo_compMask(SGateInfo *gi,const char *name) { char buf[STRMAX],*T; int p; strcpy(buf,gi->gi_name); for (p = 0,T = strtok(buf,":");T;p++, T = strtok(0,":")) if (strcmp(name,T) == 0) return spread(gi->gi_vmask,p); return 0; } /* gate types which are to be ignored. */ static void init_ignored() { int i; int N = sizeof(ignored_types)/sizeof(ignored_types[0]); for (i = 0;i < N;i++) SGateInfo_register(&ignore,ignored_types[i]); } int SGateInfo_portRank(SGateInfo *gi,const char *pname) { char buf[STRMAX]; int p; int i; if (sscanf(pname,"%[A-Za-z_]%d",buf,&p) < 2) p = 0; for (i = 0;i < gi->gi_numPads;i++) if (strcmp(buf,gi->gi_pad[i].name) == 0) return i*MAXPADPINS + p; return -1; } int Generic_checkGate(SGate *g) { int ob,i; if (g->g_ports.num < 2) { errorGate(g->g_name,"Too few pins on %s gate.",g->g_type->gi_name); return -1; } ob = g->g_ports.port[0]->p_net->n_nbits; if (g->g_ports.num == 2) { /* This is a reduction gate */ if (ob != 1) { errorGate(g->g_name,"Output on reduction gates should be single bit."); return -1; } } else { for (i = 1;i < g->g_ports.num;i++) { int ib = g->g_ports.port[i]->p_net->n_nbits; if (ib != 1 && ib != ob) { errorGate(g->g_name, "Inputs on %s gates must be single bit" " or match output bit width",g->g_type->gi_name); return -1; } } } return 0; } SGate *Generic_copyGate(SGate *sg,const char *name,SModule *M) { SGate *ng; ng = new_SGate(sg->g_typeName,name); ng->g_source = sg; ng->g_type = sg->g_type; ng->g_tech = sg->g_tech; ng->g_flags = sg->g_flags; ng->g_delayParms = sg->g_delayParms; SModule_addGate(M,ng); return ng; } void Nop_processEvent(SGate *g,EvQueue *Q,SEvent *E) { } int Nop_checkGate(SGate *g) { return 0; } void Nop_initGate(EvQueue *Q,SGate *g) { } void Generic_setProp(SGate *g,const char *name,const void *value) { #if 0 logMsg("prop: %s",name); #endif } /* * Return the delay from port Pfrom to port Pto. This can be * either a 'forward' or a 'backward' delay. Return NO_TIME, * if there is no meaningful delay value between the ports. * * If Pto is null, then this is a request for an internal * delay at a port. The default internal delay is 0. */ simTime Generic_delay(SPort *Pfrom,SPort *Pto) { int s_idx, d_idx; SGate *g = Pfrom->p_gate; SGateInfo *gi = g->g_type; simTime t = NO_TIME; int i; if (!Pto) return 0; s_idx = SPort_getPadIdx(Pfrom); d_idx = SPort_getPadIdx(Pto); assert(Pfrom->p_gate == Pto->p_gate); for (i = 0;gi->gi_delayNames[i].ds_name;i++) { SDelaySpec *ds = &gi->gi_delayNames[i]; if ((ds->ds_from & (1<ds_to == d_idx) { t = g->g_delayParms[i]; break; } if ((ds->ds_from & (1<ds_to == s_idx) { t = g->g_delayParms[i]; break; } } /* sendMsg("echo delay %s[%s(%d) -> %s(%d)] = %d",g->g_name,Pfrom->p_name,s_idx,Pto->p_name,d_idx,t);*/ return t; } void Generic_propFrwdDelay(SPort *P,simTime t) { SGate *g = P->p_gate; int k; if (SPort_effectiveType(P) != GIO_IN) return; if (t <= P->p_frwdDelay) return; P->p_frwdDelay = t; /* sendMsg("echo propFrwd %s[%s]: %d",g->g_name,P->p_name,t); */ for (k = 0;k < g->g_ports.num;k++) { SPort *P2 = g->g_ports.port[k]; simTime d; if (SPort_effectiveType(P2) != GIO_OUT) continue; if (g->g_type->gi_delay) { d = (*g->g_type->gi_delay)(P,P2); } else { d = NO_TIME; } if (d == NO_TIME) continue; SNet_propFrwdDelay(P2->p_net,d+t); } } void Generic_propBackDelay(SPort *P,simTime t) { SGate *g = P->p_gate; int k; if (SPort_effectiveType(P) != GIO_OUT) return; if (t <= P->p_backDelay) return; P->p_backDelay = t; for (k = 0;k < g->g_ports.num;k++) { SPort *P2 = g->g_ports.port[k]; simTime d; if (SPort_effectiveType(P2) != GIO_IN) continue; d = g->g_type->gi_delay ? (*g->g_type->gi_delay)(P,P2) : NO_TIME; if (d == NO_TIME) continue; SNet_propBackDelay(P2->p_net,d+t); } } void init_gates() { SHash_init(&gate_types); init_ignored(); init_process(); init_and(); init_or(); init_xor(); init_buf(); init_switch(); init_supply(); init_bufif(); init_nmos(); init_pmos(); init_add(); init_clock(); init_register(); init_flipflop(); init_mux(); init_demux(); init_concat(); init_mult(); init_div(); init_ram(); init_rom(); init_lshift(); init_rshift(); init_arshift(); init_roll(); init_tty(); init_tap(); init_led(); }