/***************************************************************
**  macro.c        commonly used functional modules           **
**  950801 TGR 0.1 (from SMM dlx1.c)                          **
**  950803 SMM 0.2 (update of RCA adder, adding left shifter) **
**  950812 SMM 0.3 (update delay of FA)                       **
**  960403 SMM 0.4 (add: Kmux, FL1u, FL1b)                    **
***************************************************************/

#include "techno.h"     /* extern decl. of basic components */

/* === Some useful functions ================================ */

int max(a, b)           /* maximum of two integers */
int a, b;
{ return (a>b) ? a:b ;
}

int ld(n)          /* log base 2, rounded to the next integer */
int n;
{ return (n<=1) ? 0:ld( (n+1)/2 ) + 1;
}

int power2(n)           /* 2^n */
int n;
{ return (n<=0) ? 1:power2( n-1 )*2 ;
}

/* === Functional Modules (Macros) ========================== */

/* --- Cost and delay of n-bit decoders: n -> 2^n ----------- */

int cdecs(n)            /* simple decoder, but slow */
int n; 
{ return (n<=1) ? cinv : cdecs(n-1) + power2(n)*cand + cinv;
}

int ddecs(n)  
int n; 
{ return (n<=1) ? dinv : max(ddecs(n-1),dinv) + dand;
}


int cdecf(n)            /* fast decoder */
int n; 
{ return (n<=1) ? cinv : 
                  cdecf(n/2) + cdecf((n+1)/2) + power2(n)*cand;
}

int ddecf(n)  
int n; 
{ return (n<=1) ? dinv : ddecf((n+1)/2) + dand;
}

/* --- Cost and delay of n-bit half-decoder: n -> 2^n ------- */

int chdec(n)  
int n; 
{ return (n<=1) ? 0 : chdec(n-1) + power2(n-1)*(cand + cor);
}

int dhdec(n)  
int n; 
{ return (n<=1) ? 0 : dhdec(n-1) + max(dand, dor);
}

/* --- Cost, delay of n-bit encoder 2^n -> n  (with flag) --- */

int cenf(n)  
int n; 
{ return (n<=1) ? cor : 2* cenf(n-1) + n*cor;
}

int denf(n)  
int n; 
{ return (n<=1) ? dor : denf(n-1) + dor;
}

/* --- Cost, delay of n-bit encoder 2^n -> n  (no flag) ----- */

int cenc(n)  
int n; 
{ return (n<=1) ? 0 : cenf(n-1) + cenc(n-1) + (n-1)*cor;
}

int denc(n)  
int n; 
{ return (n<=1) ? 0 : max(denf(n-1), denc(n-1)) + dor;
}

/* --- Cost and depth of a binary tree with n leafs --------- */

int ctree(n) 
int n; 
{ return (n-1);
}

int dtree(n) 
int n; 
{ return  ld(n);
}

/* --- Cost and delay n-bit Zero Test ----------------------- */

int czero(n) 
int n; 
{ return (n-2)*cor + cnor;
}

int dzero(n) 
int n; 
{ return  ld(n/2)*dor + dnor;
}

/* --- Cost and delay n-bit Equal Test ----------------------- */

int cEQ(n) 
int n; 
{ return n*cxor + czero(n);
}

int dEQ(n) 
int n; 
{ return  dxor + dzero(n);
}

/* --- Cost and delay n-bit Ripple Carry Incrementer -------- */
int cinc(n) 
int n; 
{ return (n-1)*(cand + cxor) + cinv;
}

int dinc(n) 
int n; 
{ return (n<=1) ? dinv : 
                  max(dinv, max((n-1)*dand, (n-2)*dand +dxor));
}

/* --- Cost and delay n-bit Conditional Ripple Carry Incr. --- */
int cincf(n) 
int n; 
{ return cinc(n/2) + cinc((n+1)/2) + (n+1)/2*cmux;
}

int dincf(n) 
int n; 
{ return dinc((n+1)/2) + dmux;
}

/* --- Cyclic left shifter ---------------------------------- */
int ccls(n) 
int n; 
{ return ld(n)*n*cmux;
}

int dcls(n) 
int n; 
{ return ld(n)*dmux;
}


/* === different adder types (RCA, CLA, CSA) ================ */

/* --- Cost and delay of Parallel Prefix, n power of 2 ------ */

int cPP(n) 
int n; 
{ return (n<=1) ? 0 : cPP(n/2) + n - 1;
}

int dPP(n) 
int n;
{ return (n<=1) ? 0 : dPP(n/2) + 2;
}

/* --- Carry look-ahead adder, n power of 2 ----------------- */
int cCLA(n) 
int n; 
{ return cPP(n)*(2*cand +cor) + (2*n+2)*cxor + (n+1)*cand + cor;
}

int dCLA(n) 
int n; 
{ return dPP(n)*(dand + dor) + 2*dxor + dand + dor;
}

/* --- Full Adder ------------------------------------------- */
int cFA() 
{ return 2*cxor + 2*cand + cor;
}

int dFAab_s() 
{ return 2*dxor;
}

int dFAabc_c() 
{ return dxor + dand + dor;
}

int dFAc_c()
{ return dand + dor;
}

int dFAc_cs()
{ return max(dxor, dand + dor);
}

int dFA()
{ return max( max( dFAab_s(), dFAabc_c()), 
              max( dFAc_c(), dFAc_cs()));
}

/* --- Ripple Carry Adder  -----------------------------------*/

int cRCA(n) 
int n; 
{ return n*cFA() + 2*cxor;
}

int dRCA(n) 
int n; 
{ if (n<=1)
   return dxor + max( max(dFAabc_c(), dFAab_s()), dFAc_cs());
  else
   return dxor + max(dFAab_s(), 
                       dFAabc_c() + (n-2)*dFAc_c() + dFAc_cs());
}
               
/* --- A2(n) adder ------------------------------------------ */

int cA2(n) 
int n; 
{ if (n<=1)
    return cxor + cxnor + cand + cor ;
  else
    return cA2(n/2) + cA2((n+1)/2) + 2*(n/2+1)* cmux;
}

int dA2(n) 
int n; 
{ if (n<=1) 
    return max( max(dxor, dxnor), max(dand, dor)) ;
  else
    return dA2((n+1)/2) + dmux; 
}

/* --- Conditions Sum Adder --------------------------------- */

int cCSA(n) 
int n; 
{ return  cA2(n) + (n+1)*cmux + 2*cxor;
}

int dCSA(n) 
int n; 
{ return dA2(n) + dmux + 2*dxor;
} 

/* --- k-fold multiplexer ----------------------------------- */
int ckmux(n,k) 
int n,k; 
{ int cost;

  if (k>2)
     cost= 2 * ckmux(n, (k+1)/2) + cmux * n;
  else 
     if (k==2)  cost= n*cmux;
     else cost= 0;
  return cost;
}

int dkmux(n,k) 
int n,k; 
{ int delay;

  if (k>2)
   delay= dkmux(n, (k+1)/2) + dmux;
  else 
    if (k==2) delay= dmux;
    else delay= 0;

  return delay;
}

/* --- Find last 1 (binary, unary output) ------------------- */

int cFL1b(n)                          /* result in binary */
int n; 
{ return (n<=1) ? 0 : 2*cFL1b((n+1)/2) + cor + ld(n)*cmux ; }

int dFL1b(n) 
int n; 
{ return (n<=1) ? 0 : dFL1b((n+1)/2) + max(dor, dmux); }

/* Clearing all bits of the input except the least significant */
/* bit  which is active                                        */
int cFL1u(n)      
int n; 
{ return (n<=1) ? cinv : 2*cFL1u((n+1)/2) + ld((n+1)/2 +1)*cand ; }

int dFL1u(n) 
int n; 
{ return (n<=1) ? dinv : dFL1u((n+1)/2) + dand; }


/* --- Find first 0 (binary output) ------------------------- */
int cFF0(N)   
int N; 
{ int n, M;
  
  if (N <= 1)
    return 0;
  else
  { n = ld(N);
    M = power2(n-1);
    return cand + (n-1)* cmux + cFF0(M) + cFF0(N-M);
  }
}

int dFF0(N)   
int N; 
{ int n, M;
  
  if (N <= 1)
    return 0;
  else
  { n = ld(N);
    M = power2(n-1);
    return max(dand, dmux) + dFF0(M);
  }
}

