/**************************************************************************** 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 ADD_Z 0 #define ADD_CO 1 #define ADD_A 2 #define ADD_B 3 #define ADD_CI 4 #define ADD_DELAY_ABZ 0 #define ADD_DELAY_ABCO 1 #define ADD_DELAY_CIZ 2 #define ADD_DELAY_CICO 3 static void Add_processEvent(SGate*,EvQueue*,SEvent*); static int Add_checkGate(SGate*); static SGateInfo add_info = { 0, "add",0x1, 5,{{"S",GIO_OUT,0}, {"CO",GIO_OUT,0}, {"A",GIO_IN,0}, {"B",GIO_IN,0}, {"CI",GIO_IN,0}}, {{"A/B-S",bit(2)|bit(3),0}, {"A/B-CO",bit(2)|bit(3),1}, {"CI-S",bit(4),0}, {"CI-CO",bit(4),1}, {0}}, Generic_copyGate, Add_processEvent, Add_checkGate, Nop_initGate, Generic_setProp, 0, 0, Generic_propFrwdDelay, Generic_propBackDelay, Generic_delay, }; void init_add() { SGateInfo_register(&add_info,0); } static int Add_checkGate(SGate *g) { SPort *Z = g->g_ports.port[ADD_Z]; SPort *CO = g->g_ports.port[ADD_CO]; SPort *A = g->g_ports.port[ADD_A]; SPort *B = g->g_ports.port[ADD_B]; SPort *CI = g->g_ports.port[ADD_CI]; int n; if (CI->p_net->n_nbits != 1 || CO->p_net->n_nbits != 1) { errorGate(g->g_name,"Carry inputs/outputs must be single bit."); return -1; } n = Z->p_net->n_nbits; if (A->p_net->n_nbits != n || B->p_net->n_nbits != n) { errorGate(g->g_name,"Inputs and output must be same bit width."); return -1; } return 0; } static void Add_processEvent(SGate *g,EvQueue *Q,SEvent *E) { SPort *Z = g->g_ports.port[ADD_Z]; SPort *CO = g->g_ports.port[ADD_CO]; SState *aS = SGate_allocPortState(g,ADD_A); SState *bS = SGate_allocPortState(g,ADD_B); SState *ciS = SGate_allocPortState(g,ADD_CI); SState *zS = alloc_SState(); SState *coS = alloc_SState(); int inUnknown = 0; int wc = (Z->p_state.nbits >> SSWORDSHIFT); /* Index # of top word */ int topnbits = Z->p_state.nbits & SSBITMASK; /* Number of bits used in top word */ unsigned mask; /* Mask for top word */ int carry_event; /* Event was carry in change */ int delay; /* Delay value */ int i; if (topnbits == 0) { wc--; topnbits = SSBITMASK+1; mask = ~0; } else mask = (1<<(topnbits))-1; SState_reinit(zS,Z->p_state.nbits); SState_reinit(coS,CO->p_state.nbits); carry_event = IsChangeOn(E,g,ADD_CI); /* * Check if there are any input bits other than 0 or 1 (unknown, floating, etc.) */ if ((ciS->flt[0] & 0x1)) inUnknown = 1; for (i = 0;i <= wc && !inUnknown;i++) { if (i == wc) { if ((aS->flt[i] & mask)) inUnknown = 1; if ((bS->flt[i] & mask)) inUnknown = 1; } else { if (aS->flt[i]) inUnknown = 1; if (bS->flt[i]) inUnknown = 1; } } if (inUnknown) { /* * If there are any unknown input bits, output unknown. */ SState_unknown(zS); SState_unknown(coS); } else { unsigned sum,carry; carry = ciS->one[0] & 0x1; /* set carry in */ for (i = 0;i <= wc;i++) { unsigned A = aS->one[i] & LMASK(aS->nbits&SSBITMASK); unsigned B = bS->one[i] & LMASK(bS->nbits&SSBITMASK); sum = A + B + carry; /* new sum value */ carry = ((B&0x1) + (A&0x1) + carry) >> 1; carry += (A>>1) + (B>>1); if (i != wc) carry >>= SSWORDSIZE-1; else carry >>= topnbits-1; zS->one[i] = sum; zS->zero[i] = ~sum; zS->flt[i] = 0; } coS->one[0] = carry; coS->zero[0] = ~carry; coS->flt[0] = 0; } if (carry_event) delay = g->g_delayParms[ADD_DELAY_CIZ]; else delay = g->g_delayParms[ADD_DELAY_ABZ]; EvQueue_setPort(Q,Z,zS,delay); if (carry_event) delay = g->g_delayParms[ADD_DELAY_CIZ]; else delay = g->g_delayParms[ADD_DELAY_ABZ]; EvQueue_setPort(Q,CO,coS,delay); free_SState(zS); free_SState(coS); free_SState(aS); free_SState(bS); free_SState(ciS); }