/**************************************************************************** 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 "gsim.h" #define CLOCK_Z 0 struct clock_data { int omega; /* Clock cycle time */ int phi; /* Phase (in %) */ int duty; /* Duty cycle (in %) */ int start; /* Start point in cycles */ int low; /* Epochs in low state */ int high; /* Epochs in high state */ }; static SGate *Clock_copyGate(SGate *sg,const char *name,SModule *M); static void Clock_processEvent(SGate*,EvQueue*,SEvent*); static void Clock_initGate(EvQueue*,SGate*); static void Clock_setProp(SGate*,const char*,const void*); static SGateInfo clock_info = { 0, "clock",0x0, 1,{{"Z",GIO_OUT,PF_CLOCK|PF_CUT}}, {{0}}, Clock_copyGate, Clock_processEvent, Nop_checkGate, Clock_initGate, Clock_setProp }; void init_clock() { SGateInfo_register(&clock_info,0); } static SGate *Clock_copyGate(SGate *sg,const char *name,SModule *M) { SGate *ng = Generic_copyGate(sg,name,M); struct clock_data *nd = (struct clock_data *) malloc(sizeof(struct clock_data)); struct clock_data *sd = (struct clock_data *) sg->g_data; ng->g_data = nd; *nd = *sd; return ng; } static void Clock_processEvent(SGate *g,EvQueue *Q,SEvent *E) { SPort *Z = g->g_ports.port[CLOCK_Z]; SState *S = &Z->p_state; struct clock_data *cd = (struct clock_data*)g->g_data; int delay; if ((S->one[0] & 0x1)) { delay = cd->low; SState_zero(S); if ((Q->flags & EVF_NEGCLOCK) && (!Q->triggerClock || Q->triggerClock == g)) { if (--Q->clockCount <= 0) { Q->flags &= ~(EVF_POSCLOCK|EVF_NEGCLOCK); EvQueue_control(Q,EVC_STOP,0,Q->clockHold); } } } else { delay = cd->high; SState_one(S); S->one[0] &= LMASK(S->nbits&SSBITMASK); if ((Q->flags & EVF_POSCLOCK) && (!Q->triggerClock || Q->triggerClock == g)) { if (--Q->clockCount <= 0) { Q->flags &= ~(EVF_POSCLOCK|EVF_NEGCLOCK); EvQueue_control(Q,EVC_STOP,0,Q->clockHold); } } } /* Needed here, because of automatic compliment in setPort function */ if (Z->p_comp) SState_not(S,S); EvQueue_setPort(Q,Z,S,0); EvQueue_qGateEv(Q,g,0,0,delay); } static void Clock_initGate(EvQueue *Q,SGate *g) { SPort *Z = g->g_ports.port[CLOCK_Z]; SState *S = alloc_SState(); struct clock_data *cd = (struct clock_data*)g->g_data; Q->flags |= EVF_HASCLOCK; SState_zero(S); if (cd->start < cd->low) { EvQueue_setPort(Q,Z,S,0); EvQueue_qGateEv(Q,g,0,0,cd->low-cd->start); } else { SState_not(S,S); EvQueue_setPort(Q,Z,S,0); EvQueue_qGateEv(Q,g,0,0,cd->high-(cd->start-cd->low)); } free_SState(S); } static void Clock_setProp(SGate *g,const char *prop,const void *value) { int n = *((int*)value); struct clock_data *cd = (struct clock_data*)g->g_data; if (!cd) { cd = (struct clock_data*)malloc(sizeof(struct clock_data)); g->g_data = cd; } if (strcmp(prop,"/omega") == 0) cd->omega = n; else if (strcmp(prop,"/phi") == 0) cd->phi = n; else if (strcmp(prop,"/duty") == 0) cd->duty = n; if (cd->phi < 0) cd->phi = 0; if (cd->phi > 99) cd->phi = 99; if (cd->duty < 1) cd->duty = 1; if (cd->duty > 99) cd->duty = 99; cd->low = (cd->omega*cd->duty)/100; if (cd->low < 1) cd->low = 1; else if (cd->low >= cd->omega) cd->low = cd->omega-1; cd->high = cd->omega - cd->low; cd->start = (cd->omega*cd->phi)/100; if (cd->start < 0) cd->start = 0; else if (cd->start >= cd->omega) cd->start = cd->omega-1; }