
#include "Sim.h"

/* =============================================================
 * Declare functions used in One_Bit_ALU()
 * ============================================================= */
void Full_Adder( const SD &coord,
                 const Signal &CarryIn, const Signal &a, const Signal &b,
                 const Signal &CarryOut, const Signal &Sum);
void Decoder2x4( const SD &coord,
                 const Signal &c, const Signal &s);


/* ================================================================
   1 bit ALU  component

     Syntax: One_Bit_ALU a b carry-in sel1 sel0 | z carry-out;
     sel1 = 0, sel0 = 0 -> Add a, b carry-in
     sel1 = 0, sel0 = 1 -> Not a
     sel1 = 1, sel0 = 0 -> a AND b
     sel1 = 1, sel0 = 1 -> a OR b
   ================================================================= */
void One_Bit_ALU(const SD &coord,
                 const Signal &a, const Signal &b, const Signal &c_in,
                 const Signal &sel,   // sel[1] sel[0]
                 const Signal &z, const Signal &c_out)
{
   Module( coord, "ALU-1", (a,b,c_in,sel), (z, c_out) );

   Signal comp_And, comp_Or, comp_Not, comp_Sum, comp_c_out;  // Compute values
   Signal l0, l1, l2, l3;    // Decoder outputs and selection signals
   Signal out_And, out_Or, out_Not, out_Sum, out_c_out;  // Output values

   /* ====================================
      Compute all the possible results...
      ==================================== */
   And( SD(coord,"aa"), (a, b),            comp_And);
   Or( SD(coord,"aa"),  (a, b),            comp_Or);
   Not( SD(coord,"aa"),  a,                comp_Not);
   Full_Adder( SD(coord,"aa"), a, b, c_in, comp_Sum, comp_c_out);


   /* ====================================
      Select out the value with a decoder
      ==================================== */
   Decoder2x4( SD(coord,"ba"), (sel[1],sel[0]),  (l3,l2,l1,l0) );

   And( SD(coord,"bc"), (l3, comp_Or ),  out_Or);
   And( SD(coord,"bc"), (l2, comp_And),  out_And);
   And( SD(coord,"bc"), (l1, comp_Not),  out_Not);
   And( SD(coord,"bc"), (l0, comp_Sum),  out_Sum);

   /* ====================================
      Form the final outputs
      ==================================== */
   And( SD(coord,"bc"), (l0,  comp_c_out),   c_out);
   Or ( SD(coord,"bc"), (out_And, out_Or, out_Not, out_Sum), z);
}



/* =============================================================
   Full_Adder() circuit

   Used inside the One-bit-ALU....
   ============================================================= */
void Full_Adder( const SD &coord,
	         const Signal &a, const Signal &b, const Signal &CarryIn, 
                 const Signal &Sum, const Signal &CarryOut)
{
   Module( coord, "FA", (CarryIn,a,b), (CarryOut,Sum) );

   Signal x, y, z;

   Xor( SD(coord,"aa"),    (a,b),        x);
   Xor( SD(coord,"ab"),    (x, CarryIn), Sum);
   And( SD(coord,"bb"),    (a, b),       y);
   And( SD(coord,"cb"),    (CarryIn, x), z);
   Or ( SD(coord,"bc-cc"), (y, z),       CarryOut);
}



/* ============================================================
   A 2x4 decoder that is used in the One_Bit_ALU circuit

   Input:    c:   c[1] c[0]
   Output:   One of s[3], s[2], s[1], s[0] is 1, all other = 0
   ============================================================ */
void Decoder2x4( const SD &coord,
                 const Signal &c, const Signal &s)
{

   Signal not_c0, not_c1;

   Module( coord, "Decoder", (c[1],c[0]), (s[3]-s[0]) );

   Not( SD(coord,"aa"), c[1], not_c1);
   Not( SD(coord,"ba"), c[0], not_c0);

   And( SD(coord,"ba"), (c[1],   c[0]),   s[3]);
   And( SD(coord,"bb"), (c[1],   not_c0), s[2]);
   And( SD(coord,"bc"), (not_c1, c[0]),   s[1]);
   And( SD(coord,"bd"), (not_c1, not_c0), s[0]);
}



void simnet()
{
   Signal a[4], b[4], c[4];
   Sig(sel,2);
   Sig(z,4);
   Sig(c_out,1);

   /* ===================================================
      Two  4 bit input numbers
      =================================================== */
   Switch("ab", a[3], '3', Zero); 
   Switch("ac", a[2], '2', Zero); 
   Switch("ad", a[1], '1', Zero); 
   Switch("ae", a[0], '0', Zero); 

   Switch("ah", b[3], '7', Zero); 
   Switch("ai", b[2], '6', Zero); 
   Switch("aj", b[1], '5', Zero); 
   Switch("ak", b[0], '4', Zero); 

   Switch("ea", sel[1], 'a', Zero);    // Select 1
   Switch("eb", sel[0], 'b', Zero);    // Select 0

   One_Bit_ALU("ch", a[0], b[0], Zero, sel, z[0], c[0]);
   One_Bit_ALU("cg", a[1], b[1], c[0], sel, z[1], c[1]);
   One_Bit_ALU("cf", a[2], b[2], c[1], sel, z[2], c[2]);
   One_Bit_ALU("ce", a[3], b[3], c[2], sel, z[3], c_out);

   /* ======================================================
      Probe outputs
      ====================================================== */
   Probe("eh", z[0]);
   Probe("eg", z[1]);
   Probe("ef", z[2]);
   Probe("ee", z[3]);

   Probe("ca", c_out);
}



