/**************************************************************************

  This is a simple tree arbiter, adapted from Dills' thesis p 89.
  There are four processors which
  share a single resource. A token defines which processor has the 
  resource. The arbiter cells have two children and one parent. 
  An arbiter can request the token, release it, etc.

  Adnan Aziz
  July 10, 1996
  UT Austin

***************************************************************************/ 

/*
 * Symbolic variables.
 *
 */
typedef enum {myTRUE, myFALSE} boolean;
typedef enum {idle, request, lock, release} handShakeType;

/*
 * The inteconnections between the processors and the cells.
 *
 */
module main( clk );
input clk;

boolean wire xa, ya, sa;  
handShakeType wire xr, yr, sr;

boolean wire constTRUE;


assign sa = myFALSE;
assign constTRUE = myTRUE;

arbitCell F0(  clk, constTRUE, xr,  yr,  xa,  ya, sr, sa );
fourCells G1( clk, xa, xr );
fourCells G2( clk, ya, yr );

endmodule


module fourCells( clk, sa, sr );
input clk;
input sa;
output sr;

boolean       wire ua1, ua2, ua3, ua4, xa, ya, sa;
handShakeType wire ur1, ur2, ur3, ur4, xr, yr, sr;

wire[0:1] procChoice;

boolean wire constTRUE, constFALSE;

assign constTRUE  = myTRUE;
assign constFALSE = myFALSE;

arbitCell C0 ( clk, constFALSE,  xr,  yr,  xa,  ya,  sr, sa );
arbitCell C1 ( clk, constFALSE, ur1, ur2, ua1, ua2, xr, xa );
arbitCell C2 ( clk, constFALSE, ur3, ur4, ua3, ua4, yr, ya ); 

procModel P1( clk, ua1, ur1 ); 
procModel P2( clk, ua2, ur2 ); 
procModel P3( clk, ua3, ur3 ); 
procModel P4( clk, ua4, ur4 ); 

endmodule


/* 
 * The arbiter cell has two inputs from children and two outputs to chidren.
 * One input from parent, and one output to parent. The latch holdToken corresponds
 * to whether the cell holds the token. The latches prevLeft and prevRight are
 * used to keep track of which way the token went last, to impart fairness
 * in the scheduling of the children.
 *
 */


/*
 * Add comments
 */
module procModel(clk, ack, req );
input clk;
input ack;
output req;

boolean wire ack;
handShakeType wire req;
wire randChoice;

assign req = procState;
assign randChoice = $ND(0,1);

handShakeType reg procState;

initial procState = idle;

always @(posedge clk) begin
    
    if ( procState == idle  && (randChoice == 1) )
        begin 
	    procState = request;
        end
    else if ( procState == request && ack == myTRUE )
        begin 
	    procState = lock;
        end
    else if (  procState == lock && (randChoice == 1 ) ) 
        begin 
            procState = release;
        end
    else if ( procState == release )
        begin
            procState = idle;
        end
end

endmodule



module arbitCell(clk, topCell, urLeft, urRight, uaLeft, uaRight, xr, xa);
input clk;
input topCell, urLeft, urRight, xa;
output uaLeft, uaRight, xr;

boolean       wire topCell, uaLeft, uaRight, xa; 
handShakeType wire urLeft, urRight, xr; 

boolean wire uaLeft, uaRight;

boolean reg prevLeft, prevRight;
initial prevLeft = myFALSE;
initial prevRight = myTRUE;

boolean reg processedLeft, processedRight;
initial processedLeft = myFALSE;
initial processedRight = myFALSE;

boolean wire mustGiveParent; /* essentially a macro for checking if must release the token to parent */
assign mustGiveParent = ( processedLeft == myTRUE ) && ( processedRight == myTRUE )  
                                              && ( !( topCell == myTRUE ) ) ? myTRUE : myFALSE;

boolean reg holdToken;
initial holdToken = topCell;

boolean wire childOwns; /* essentially a macro for checking if a descendant owns the token */
assign childOwns = ( urLeft == lock || urRight == lock ) ? myTRUE : myFALSE;

boolean wire giveChild; /* essentially a macro for checking if a child is being given the token */
assign giveChild = ( uaLeft == myTRUE  || uaRight == myTRUE ) ? myTRUE : myFALSE;

/*
 * Condition under which the token is given to the left child
 * Must own token, have request from left, and either no request from right or if there is
 * a request from the right it, should be lefts turn (since right went the last time 
 *
 */
assign uaLeft = ( !( mustGiveParent == myTRUE ) && ( holdToken == myTRUE && urLeft == request  
                    && ( ! ( urRight == request ) || prevRight == myTRUE ) ) ) ? myTRUE : myFALSE;

/*
 * same as above for right 
 *
 */
assign uaRight = ( !( mustGiveParent == myTRUE ) && ( holdToken == myTRUE && urRight == request  
                    && ( ! ( urLeft == request ) || prevLeft == myTRUE ) ) ) ? myTRUE : myFALSE;

/* 
 * signal to parent: 
 *
 *   1. request if dont own the token,
 *   2. lock if descendant has locked the token
 *   3. release if child has released token
 *   4. idle otherwise 
 *
 */
assign xr = ( holdToken == myFALSE  &&  ( urLeft == request || urRight == request ) )
	        ? request :
                    ( childOwns == myTRUE )
                     ? lock :
                      ( holdToken == myTRUE && ( ( ( mustGiveParent == myTRUE ) ||
                                                   ! ( ( urLeft == request || urRight == request ) ) )
                        && !( topCell == myTRUE ) ) )
                          ? release : idle;

always @(posedge clk) begin

/*
 * keep track of whether we hold the token or not
 *
 */

    if ( xa == myTRUE )
        begin
  	    holdToken = myTRUE;
        end
    else if ( giveChild == myTRUE )
        begin 
	    holdToken = myFALSE;
        end
    else if ( urLeft == release  || urRight == release )
        begin 
	    holdToken = myTRUE;
        end
   else if ( xr == release )
        begin 
	    holdToken = myFALSE;
        end

/* 
 * keep track of which child got the token last
 *
 */
   if ( uaLeft == myTRUE ) 
       begin
           prevLeft  = myTRUE;
           prevRight = myFALSE;
       end
    else if ( uaRight == myTRUE )
       begin
           prevLeft  = myFALSE;
           prevRight = myTRUE;
       end

/* 
 * child has finished processing the token
 *
 */

   if ( urLeft == release )
     begin
	processedLeft = myTRUE;
     end
   else if ( urRight == release )
      begin
	processedRight = myTRUE;
      end
/*
 * if we have given the token to both children, must now give it up
 *
 */
   else if ( ( processedLeft == myTRUE ) && ( processedRight == myTRUE ) )
	begin
	    processedLeft = myFALSE;
            processedRight = myFALSE;
        end
         
end

endmodule
