/**************************************************************************** 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 REG_Q 0 #define REG_D 1 #define REG_EN 2 #define REG_CLR 3 #define REG_CK 4 #define REG_DELAY_SETUP 0 #define REG_DELAY_HOLD 1 #define REG_DELAY_OUT 2 struct reg_data { int last_change; /* Time of last data change */ int hold_wait; /* Hold wait until this time */ SState state; /* Register state */ }; static void Register_processEvent(SGate*,EvQueue*,SEvent*); static int Register_checkGate(SGate*); static void Register_initGate(EvQueue*,SGate*); static simTime Register_delay(SPort *Pfrom,SPort *Pto); static SGateInfo reg_info = { 0, "register",0x0, 5,{{"Q",GIO_OUT,PF_CUT}, {"D",GIO_IN,PF_CUT}, {"EN",GIO_IN,PF_CUT}, {"CLR",GIO_IN,PF_CUT}, {"CK",GIO_IN,PF_CLOCK|PF_CUT}}, {{"setup",bit(1),-1}, {"hold",0,-1}, {"CK-Q",0,1}, {0}}, Generic_copyGate, Register_processEvent, Register_checkGate, Register_initGate, Generic_setProp, 0, 0, 0, 0, Register_delay }; #if 0 static void Register_processEvent(SGate *g,EvQueue *Q,SEvent *E) { SPort *Z = g->g_ports.port[REG_Q]; struct reg_data *rd = (struct reg_data*) g->g_data; SState *CLR = SGate_allocPortState(g,REG_CLR); int clr = SState_getBitSym(CLR,0); int hold_delay, out_delay, setup_delay; hold_delay = g->g_delayParms[REG_DELAY_HOLD]; out_delay = g->g_delayParms[REG_DELAY_OUT]; setup_delay = g->g_delayParms[REG_DELAY_SETUP]; free_SState(CLR); if (IsChangeOn(E,g,REG_D)) { /* Data in changed */ if (Q->curStep < rd->hold_wait) { /* Data changed to soon after clock */ SState_unknown(&rd->state); EvQueue_setPort(Q,Z,&rd->state,out_delay); } else { rd->last_change = Q->curStep; /* Mark time of last data change */ } } /* * If clear line is set, set register to zero. */ if (clr == SYM_ZERO) { SState_zero(&rd->state); EvQueue_setPort(Q,Z,&rd->state,out_delay); return; } /* * If clear line is unknown, set register to unknown. */ if (clr != SYM_ONE) { SState_unknown(&rd->state); EvQueue_setPort(Q,Z,&rd->state,out_delay); return; } /* * Check for clock transition. */ if (IsChangeOn(E,g,REG_CK)) { SState *CK = SGate_allocPortState(g,REG_CK); SState *EN = SGate_allocPortState(g,REG_EN); int en = SState_getBitSym(EN,0); int ck = SState_getBitSym(CK,0); free_SState(EN); free_SState(CK); switch (en) { case SYM_ZERO : /* Clock is enabled */ switch (ck) { case SYM_ONE : /* Positive clock edge */ if (Q->curStep < rd->last_change+setup_delay) { SState_unknown(&rd->state); } else { SState *D = SGate_allocPortState(g,REG_D); SState_copy(&rd->state,D); rd->hold_wait = Q->curStep + hold_delay; free_SState(D); } break; case SYM_ZERO : /* Negative clock edge */ break; default : /* Bogus clock value */ SState_unknown(&rd->state); break; } break; case SYM_ONE : /* Clock is disabled */ break; default : SState_unknown(&rd->state); break; } EvQueue_setPort(Q,Z,&rd->state,out_delay); } } #endif #if 1 static void Register_processEvent(SGate *g,EvQueue *Q,SEvent *E) { SPort *Z = g->g_ports.port[REG_Q]; struct reg_data *rd = (struct reg_data*) g->g_data; SState *CLR = SGate_allocPortState(g,REG_CLR); int clr = SState_getBitSym(CLR,0); int hold_delay, out_delay, setup_delay; SState *S = alloc_SState(); int do_set = 0; hold_delay = g->g_delayParms[REG_DELAY_HOLD]; out_delay = g->g_delayParms[REG_DELAY_OUT]; setup_delay = g->g_delayParms[REG_DELAY_SETUP]; free_SState(CLR); if (IsChangeOn(E,g,REG_D)) { /* Data in changed */ if (Q->curStep < rd->hold_wait) { /* Data changed to soon after clock */ SState_unknown(&rd->state); SState_copy(S,&rd->state); do_set = 1; } else { rd->last_change = Q->curStep; /* Mark time of last data change */ } } if (clr == SYM_ZERO) { /* * If clear line is set, set register to zero. */ SState_zero(&rd->state); SState_copy(S,&rd->state); do_set = 1; } else if (clr != SYM_ONE) { /* * If clear line is unknown, set register to unknown. */ SState_unknown(&rd->state); SState_copy(S,&rd->state); do_set = 1; } else if (IsChangeOn(E,g,REG_CK)) { /* * Check for clock transition. */ SState *CK = SGate_allocPortState(g,REG_CK); SState *EN = SGate_allocPortState(g,REG_EN); int en = SState_getBitSym(EN,0); int ck = SState_getBitSym(CK,0); free_SState(EN); free_SState(CK); switch (en) { case SYM_ZERO : /* Clock is enabled */ switch (ck) { case SYM_ONE : /* Positive clock edge */ if (Q->curStep < rd->last_change+setup_delay) { SState_unknown(&rd->state); } else { SState *D = SGate_allocPortState(g,REG_D); SState_copy(&rd->state,D); rd->hold_wait = Q->curStep + hold_delay; free_SState(D); } do_set = 1; break; case SYM_ZERO : /* Negative clock edge */ break; default : /* Bogus clock value */ SState_unknown(&rd->state); do_set = 1; break; } break; case SYM_ONE : /* Clock is disabled */ break; default : SState_unknown(&rd->state); do_set = 1; break; } SState_copy(S,&rd->state); } else do_set = 0; if (do_set) { EvQueue_setPort(Q,Z,S,out_delay); } free_SState(S); } #endif static simTime Register_delay(SPort *Pfrom,SPort *Pto) { SGate *g = Pfrom->p_gate; if (Pto) return 0; switch (Pfrom->p_type->idx) { case REG_Q : return g->g_delayParms[REG_DELAY_OUT]; case REG_D : case REG_EN : case REG_CLR : return g->g_delayParms[REG_DELAY_SETUP]; case REG_CK : return 0; default: return 0; } } static int Register_checkGate(SGate *g) { return 0; } static void Register_initGate(EvQueue *Q,SGate *g) { struct reg_data *rd = (struct reg_data*) malloc(sizeof(struct reg_data)); g->g_data = rd; rd->last_change = 0; rd->hold_wait = 0; SState_init(&rd->state,g->g_ports.port[REG_Q]->p_net->n_nbits); SState_unknown(&rd->state); } void init_register() { SGateInfo_register(®_info,0); }