/**************************************************************************** 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 DIV_Q 0 #define DIV_R 1 #define DIV_A 2 #define DIV_B 3 #define DIV_DELAY_IQ 0 #define DIV_DELAY_IR 1 #if USELONGLONG #define DIV_MAXBITS (2*SSWORDSIZE) #else #define DIV_MAXBITS SSWORDSIZE #endif static void Div_processEvent(SGate*,EvQueue*,SEvent*); static int Div_checkGate(SGate*); static SGateInfo div_info = { 0, "div",0x1, 4,{{"Q",GIO_OUT,0}, {"R",GIO_OUT,0}, {"A",GIO_IN,0}, {"B",GIO_IN,0}}, {{"A/B-Q",bit(2)|bit(3),0}, {"A/B-R",bit(2)|bit(3),1}, {0}}, Generic_copyGate, Div_processEvent, Div_checkGate, Nop_initGate, Generic_setProp, 0, 0, Generic_propFrwdDelay, Generic_propBackDelay, Generic_delay, }; void init_div() { SGateInfo_register(&div_info,0); } static int Div_checkGate(SGate *g) { SPort *Q = g->g_ports.port[DIV_Q]; SPort *R = g->g_ports.port[DIV_R]; SPort *A = g->g_ports.port[DIV_A]; SPort *B = g->g_ports.port[DIV_B]; if (Q->p_net->n_nbits > DIV_MAXBITS || R->p_net->n_nbits > DIV_MAXBITS || A->p_net->n_nbits > DIV_MAXBITS || B->p_net->n_nbits > DIV_MAXBITS) { errorGate(g->g_name,"Divider inputs/outputs greater than %s bits unsupported.",DIV_MAXBITS); return -1; } return 0; } static void Div_processEvent(SGate *g,EvQueue *evQ,SEvent *E) { SPort *Q = g->g_ports.port[DIV_Q]; SPort *R = g->g_ports.port[DIV_R]; SState *aS = SGate_allocPortState(g,DIV_A); SState *bS = SGate_allocPortState(g,DIV_B); SState *qS = alloc_SState(); SState *rS = alloc_SState(); SState_reinit(qS,Q->p_state.nbits); SState_reinit(rS,R->p_state.nbits); if (!SState_isValue(aS) || !SState_isValue(bS)) { SState_unknown(qS); SState_unknown(rS); } else { #if USELONGLONG unsigned long long A,B,q,r; if (aS->nbits > SSWORDSIZE) A = aS->one[0] | ((((unsigned long long)aS->one[1]) << SSWORDSIZE)&LMASK(aS->nbits&SSBITMASK)); else A = aS->one[0] & LMASK(aS->nbits); if (bS->nbits > SSWORDSIZE) B = bS->one[0] | ((((unsigned long long)bS->one[1]) << SSWORDSIZE)&LMASK(bS->nbits&SSBITMASK)); else B = bS->one[0] & LMASK(bS->nbits); if (B) { q = A / B; r = A % B; } else q = r = 0; qS->one[0] = q; qS->zero[0] = ~q; qS->flt[0] = 0; if (qS->nbits > SSWORDSIZE) { q >>= SSWORDSIZE; qS->one[1] = q; qS->zero[1] = ~q; qS->flt[1] = 0; } rS->one[0] = r; rS->zero[0] = ~r; rS->flt[0] = 0; if (rS->nbits > SSWORDSIZE) { r >>= SSWORDSIZE; rS->one[1] = r; rS->zero[1] = ~r; rS->flt[1] = 0; } #else unsigned A,B,q,r; A = aS->one[0] & LMASK(aS->nbits); B = bS->one[0] & LMASK(bS->nbits); if (B) { q = A / B; r = A % B; } else q = r = 0; qS->one[0] = q; qS->zero[0] = ~q; qS->flt[0] = 0; rS->one[0] = q; rS->zero[0] = ~q; rS->flt[0] = 0; #endif } EvQueue_setPort(evQ,Q,qS,g->g_delayParms[DIV_DELAY_IQ]); EvQueue_setPort(evQ,R,rS,g->g_delayParms[DIV_DELAY_IR]); free_SState(aS); free_SState(bS); free_SState(rS); free_SState(qS); }