/*
 *  Copyright 2011 OpenSourceStewardshipFoundation.org
 *  Licensed under GNU General Public License version 2
 *
 * Author: seanhalle@yahoo.com
 *
 */
#include "HWSim__PingPong__HWDef/HWSim__PingPong__HWDef.h"
 
/* is an expr resolves to an actual commPath struct instance
 */
#define setCommPathValuesTo( commPath, fromElIdx, outPort, toElIdx, inPort)\
do{\
   commPath->idxOfFromElem     = fromElIdx; \
   commPath->idxOfFromOutPort  = outPort; \
   commPath->idxOfToElem       = toElIdx; \
   commPath->idxOfToInPort     = inPort; \
 }while(0); //macro magic for namespace



HWSimActivityType* createPingPongActivityType (); 

HWSimElem* createAPingPongElem (HWSimNetlist *netlist);

/*This file constructs the netlist for the Hello World circuit, which is
 * used during design and implementation of the HWSim language
 *
 *It has two elements, each with one input port and one output port, and
 * a single activity-type.
 *
 *The elements are cross-coupled, so output port of one connects to input
 * port of the other.  The input port has a single trigger, which fires
 * the one activity-type.
 *
 *The activity does nothing, except send a NULL message on the output port.
 *The activity-sim-time and communication-sim-time are both constants.
 *
 *Note that elements are generic.  They are specialized by declaring
 * inports and outports, and by registering triggers that fire particular
 * activity-types.
 */
HWSimNetlist *createPingPongNetlist()
 { HWSimNetlist   *netlist;
   HWSimCommPath  **commPaths;
   HWSimElem **elems;
   int32 numElems;
   int32 numCommPaths;
   
   netlist = malloc( sizeof(HWSimNetlist) );
   numElems= 2; 
   elems = malloc( numElems * sizeof(HWSimElem *) );
   netlist->numElems = numElems;
   netlist->elems    = elems;
   netlist->numActivityTypes = 1;
   netlist->activityTypes = malloc(netlist->numActivityTypes*sizeof(HWSimActivityType*));

   netlist->activityTypes[PING_PONG_ACTIVITY] = createPingPongActivityType();
	
   elems[0] = createAPingPongElem( netlist ); //use activity types from netlist
   elems[1] = createAPingPongElem( netlist ); 
   
      //make reset trigger an action on one of the elements
   elems[1]->inPorts[-1].triggeredActivityType =
              netlist->activityTypes[PING_PONG_ACTIVITY];
			  
   /*OutPorts and InPorts may have many commPaths attached.
    *  but an inPort only     
    * has one kind of activity that all incoming communications trigger.  That
    * activity can be zero time and then switch on the type of message then
    * end with a continuation, where the continuation activity is chosen by the    
    * switch. 
    *So, a commPath only connects an out port to an in port
    *The format is: sending elem-index, out-port, dest elem-index, in-port
    */
   numCommPaths          = 2;
   commPaths             = malloc( numCommPaths * sizeof(HWSimCommPath *) );
   netlist->numCommPaths= numCommPaths;
   netlist->commPaths= commPaths;
      //elem 0, out-port 0 to elem 1, in-port 0
   commPaths[0]= malloc(sizeof(HWSimCommPath));
   setCommPathValuesTo(commPaths[0],0,0,1,0);
   commPaths[0]->hasFixedTiming  = TRUE;
   commPaths[0]->fixedFlightTime = 10; //all time is stated in (integer) units

      //elem 1, out-port 0 to elem 0, in-port 0
   commPaths[1]= malloc(sizeof(HWSimCommPath));
   setCommPathValuesTo(commPaths[1], 1,0,0,0);
   commPaths[1]->hasFixedTiming  = TRUE;
   commPaths[1]->fixedFlightTime = 10; //all time is stated in (integer) units
   
   //TODO: decide how to do bidirectional commPaths, like connection to a bus
   // thinking make it two separate commPaths with guard between in-port and out-port

	return netlist;
 }


/*
 */
void
freePingPongNetlist (HWSimNetlist *netlist) 
 { int i;
 
   for( i = 0; i < netlist->numCommPaths; i++ )
    { free(netlist->commPaths[i]);
    }	
   free(netlist->commPaths);
   for( i= 0; i < netlist->numElems; i++ ) 
    { HWSim_ext__free_inPortsArray( netlist->elems[i]->inPorts );
      free(netlist->elems[i]->outPorts);
      free(netlist->elems[i]);
    }

   free(netlist->activityTypes);
   free(netlist->elems);
   free(netlist);
 }
 
HWSimElem *
createAPingPongElem( HWSimNetlist *netlist )
 { HWSimElem *elem;
   elem = malloc( sizeof(HWSimElem) );
   elem->numInPorts  = 1;
   elem->numOutPorts = 1;
   elem->inPorts = HWSim_ext__make_inPortsArray( elem->numInPorts );
   elem->inPorts[-1].triggeredActivityType = IDLE_SPAN; //reset port
   elem->inPorts[0].triggeredActivityType  = netlist->activityTypes[PING_PONG_ACTIVITY];
	return elem;
 }
 
HWSimActivityType *
createPingPongActivityType( )
 { HWSimActivityType *pingPongActivityType;
   pingPongActivityType = malloc( sizeof(HWSimActivityType) );
   
   pingPongActivityType->hasBehavior   = TRUE;
   pingPongActivityType->hasTiming     = TRUE;
   pingPongActivityType->timingIsFixed = TRUE;
   pingPongActivityType->fixedTime     = 10;
   pingPongActivityType->behaviorFn    = &pingPongElem_PingActivity_behavior;
   return pingPongActivityType;
 }
 
