
#include <stdint.h>
#include <systemc>
#include <sys/time.h>
#include <iostream>
#include <cstdlib>
#include <cstdarg>

#include "arithmetics.h"
#include "mapping_table.h"
#include "alloc_elems.h"
#include "vci_synthetic_target.h"
#include "vci_local_ring_fast.h"
#include "virtual_dspin_router.h"
#include "vci_synthetic_initiator.h"

// MESH SIZE
#define X_MAX           2
#define Y_MAX           2
#define N_CLUSTERS      X_MAX*Y_MAX
// FLIT_WIDTH
#define WIDTH_CMD	40
#define WIDTH_RSP	33
// Face of each DSPIN Router
#define NORTH		0
#define SOUTH		1
#define EAST		2
#define WEST		3
#define LOCAL		4
// VCI parameters
#define cell_width      4
#define plen_width      8
#define address_width   32
#define error_width     1
#define clen_width      1
#define rflag_width     1
#define srcid_width     11
#define pktid_width     4
#define trdid_width     4
#define wrplen_width    1
// Adress of targets
#define TARGET_ADDR	0x00000000
#define TARGET_SIZE	0x400
// FIFO depth in the gateways
#define DEPTH		4
// LENGTH of packets
#define PACKET_LENGTH	2
// FIFO depth in the routers
#define DSPIN_FIFO      4
// DEBUG MODE : 0 OFF, 1 only the initiators and the targets, 2 only network
#define DEBUG		0
// LOAD wanted
#define LOAD		450

#define STAGE		0

int _main(int argc, char *argv[])
{
	using namespace sc_core;
	// Avoid repeating these everywhere
	using soclib::common::IntTab;
	using soclib::common::Segment;

	using soclib::common::uint32_log2;

	int ncycles;
	uint32_t rho_a;
	uint32_t rho_b;

	if(argc == 4){
	  ncycles = std::atoi(argv[1]);
	  rho_a = std::atoi(argv[2]);
	  rho_b = std::atoi(argv[3]);
	} else {
	  std::cout << "Usage : simulation_cycles packet_rate broadcast_period" << std::endl;
	  exit(1);
	}
	// Define VCI parameters
	typedef soclib::caba::VciParams<cell_width,
					plen_width,
					address_width,
					error_width,
					clen_width,
					rflag_width,
					srcid_width,
					pktid_width,
					trdid_width,
					wrplen_width> vci_param;

	// Mapping table primary network
	soclib::common::MappingTable maptab0(address_width, IntTab(soclib::common::uint32_log2(X_MAX)+soclib::common::uint32_log2(Y_MAX) ,srcid_width-soclib::common::uint32_log2(X_MAX)-soclib::common::uint32_log2(Y_MAX)),
							    IntTab(soclib::common::uint32_log2(X_MAX)+soclib::common::uint32_log2(Y_MAX) ,srcid_width-soclib::common::uint32_log2(X_MAX)-soclib::common::uint32_log2(Y_MAX)), 0xFFC0000);
	soclib::common::MappingTable maptab1(address_width, IntTab(soclib::common::uint32_log2(X_MAX)+soclib::common::uint32_log2(Y_MAX) ,srcid_width-soclib::common::uint32_log2(X_MAX)-soclib::common::uint32_log2(Y_MAX)),
							    IntTab(soclib::common::uint32_log2(X_MAX)+soclib::common::uint32_log2(Y_MAX) ,srcid_width-soclib::common::uint32_log2(X_MAX)-soclib::common::uint32_log2(Y_MAX)), 0xFFC0000);
	for(int i = 0 ; i < Y_MAX ; i++){
		for(int j = 0 ; j < X_MAX ; j++){
			std::ostringstream	str0;
			std::ostringstream	str1;
			str0 << "Target_c0_" << (i*Y_MAX+j) ;
			str1 << "Target_c1_" << (i*Y_MAX+j) ;
			maptab0.add(Segment(str0.str(), TARGET_ADDR + ((i*Y_MAX+j) << (address_width-soclib::common::uint32_log2(X_MAX)-soclib::common::uint32_log2(Y_MAX))), TARGET_SIZE, IntTab((i*X_MAX+j),0), false));
			maptab1.add(Segment(str1.str(), TARGET_ADDR + ((i*Y_MAX+j) << (address_width-soclib::common::uint32_log2(X_MAX)-soclib::common::uint32_log2(Y_MAX))), TARGET_SIZE, IntTab((i*X_MAX+j),0), false));
		}
	}


	sc_clock	signal_clk("clk");
	sc_signal<bool> signal_resetn("resetn");
   
	soclib::caba::VciSignals<vci_param> ** signal_vci_ini_synth_c0 = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_ini_synth_c0", 2, N_CLUSTERS);
	soclib::caba::VciSignals<vci_param> ** signal_vci_ini_synth_c1 = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_ini_synth_c1", 2, N_CLUSTERS);
	///////////////////////////////////////////////////////////////
	// VDSPIN Signals : one level for in and out, one level for X length in the mesh, 
	//                  one level for Y length in the mesh, last level for each port of the router
	///////////////////////////////////////////////////////////////
	soclib::caba::DspinSignals<WIDTH_CMD> **** dspin_signals_cmd_c0 = soclib::common::alloc_elems<soclib::caba::DspinSignals<WIDTH_CMD> >("Dspin_cmd_signals_channel_0", 2, X_MAX, Y_MAX, 5 );
	soclib::caba::DspinSignals<WIDTH_CMD> **** dspin_signals_cmd_c1 = soclib::common::alloc_elems<soclib::caba::DspinSignals<WIDTH_CMD> >("Dspin_cmd_signals_channel_1", 2, X_MAX, Y_MAX, 5 );
	soclib::caba::DspinSignals<WIDTH_RSP> **** dspin_signals_rsp_c0 = soclib::common::alloc_elems<soclib::caba::DspinSignals<WIDTH_RSP> >("Dspin_rsp_signals_channel_0", 2, X_MAX, Y_MAX, 5 );
	soclib::caba::DspinSignals<WIDTH_RSP> **** dspin_signals_rsp_c1 = soclib::common::alloc_elems<soclib::caba::DspinSignals<WIDTH_RSP> >("Dspin_rsp_signals_channel_2", 2, X_MAX, Y_MAX, 5 );


	// N_CLUSTERS ring.
	soclib::caba::VciLocalRingFast<vci_param, WIDTH_CMD, WIDTH_RSP> * local_ring_c0 = (soclib::caba::VciLocalRingFast<vci_param, WIDTH_CMD, WIDTH_RSP> *) malloc(sizeof(soclib::caba::VciLocalRingFast<vci_param, WIDTH_CMD, WIDTH_RSP> ) * N_CLUSTERS) ;
	soclib::caba::VciLocalRingFast<vci_param, WIDTH_CMD, WIDTH_RSP> * local_ring_c1 = (soclib::caba::VciLocalRingFast<vci_param, WIDTH_CMD, WIDTH_RSP> *) malloc(sizeof(soclib::caba::VciLocalRingFast<vci_param, WIDTH_CMD, WIDTH_RSP> ) * N_CLUSTERS) ;
	for(int i = 0 ; i < N_CLUSTERS ; i++){                                                            // ringid, fifo, fifo, nb_init, nb_tgt
		std::ostringstream	str0;
		std::ostringstream	str1;
		str0 << "cluster_c0_" << i ;
		str1 << "cluster_c1_" << i ;
		new(&local_ring_c0[i]) soclib::caba::VciLocalRingFast<vci_param, WIDTH_CMD, WIDTH_RSP> (str0.str().c_str(),
													maptab0, 
													IntTab(i), 
													2, 
													DEPTH, 
													1, 
													1);
		new(&local_ring_c1[i]) soclib::caba::VciLocalRingFast<vci_param, WIDTH_CMD, WIDTH_RSP> (str1.str().c_str(), 
													maptab1, 
													IntTab(i), 
													2, 
													DEPTH,
													1,
													1);
	}

	// Virtual dspin routers
	soclib::caba::VirtualDspinRouter<WIDTH_CMD> ** routers_cmd = (soclib::caba::VirtualDspinRouter<WIDTH_CMD> **) malloc(sizeof(soclib::caba::VirtualDspinRouter<WIDTH_CMD> *) * X_MAX);
	soclib::caba::VirtualDspinRouter<WIDTH_RSP> ** routers_rsp = (soclib::caba::VirtualDspinRouter<WIDTH_RSP> **) malloc(sizeof(soclib::caba::VirtualDspinRouter<WIDTH_RSP> *) * X_MAX);

	for(int i = 0; i < X_MAX; i++ ){
	  routers_cmd[i] = (soclib::caba::VirtualDspinRouter<WIDTH_CMD> * ) malloc(sizeof(soclib::caba::VirtualDspinRouter<WIDTH_CMD>) * Y_MAX);
	  routers_rsp[i] = (soclib::caba::VirtualDspinRouter<WIDTH_RSP> * ) malloc(sizeof(soclib::caba::VirtualDspinRouter<WIDTH_RSP>) * Y_MAX);
	  for(int j = 0; j < Y_MAX; j++){
		  std::ostringstream	str0;
		  std::ostringstream	str1;
		  str0 << "VDspinRouterCMD" << i << j;
		  str1 << "VDspinRouterRSP" << i << j;
		  new(&routers_cmd[i][j]) soclib::caba::VirtualDspinRouter<WIDTH_CMD> (str0.str().c_str(), i, j, soclib::common::uint32_log2(X_MAX), soclib::common::uint32_log2(Y_MAX), DSPIN_FIFO, DSPIN_FIFO);
		  new(&routers_rsp[i][j]) soclib::caba::VirtualDspinRouter<WIDTH_RSP> (str1.str().c_str(), i, j, soclib::common::uint32_log2(X_MAX), soclib::common::uint32_log2(Y_MAX), DSPIN_FIFO, DSPIN_FIFO);
	  }
	}


	///////////////////////////////////////////////////////////////
	// Components
	///////////////////////////////////////////////////////////////

	// N_CLUSTERS VCI Synthetic Initiator (1 initiator per cluster/network)
	soclib::caba::VciSyntheticInitiator<vci_param> * initiator_c0 = (soclib::caba::VciSyntheticInitiator<vci_param> *) malloc(sizeof(soclib::caba::VciSyntheticInitiator<vci_param> )* N_CLUSTERS);
	soclib::caba::VciSyntheticInitiator<vci_param> * initiator_c1 = (soclib::caba::VciSyntheticInitiator<vci_param> *) malloc(sizeof(soclib::caba::VciSyntheticInitiator<vci_param> )* N_CLUSTERS);
	for(int i = 0 ; i < X_MAX; i++)
		for(int j = 0 ; j < Y_MAX ; j++){
			std::ostringstream	str0;
			std::ostringstream	str1;
			str0 << "Initiator_c0_" << i << "_" << j ;
			str1 << "Initiator_c1_" << i << "_" << j ;
			new(&initiator_c0[Y_MAX*i+j]) soclib::caba::VciSyntheticInitiator<vci_param> (str0.str().c_str() , maptab0, IntTab((i*Y_MAX+j) ,0), PACKET_LENGTH, 0, 100, X_MAX, Y_MAX); 
#if STAGE==1
			if( (i + 1 == X_MAX) && (j + 1 == Y_MAX ) )
#endif
			    new(&initiator_c1[Y_MAX*i+j]) soclib::caba::VciSyntheticInitiator<vci_param> (str1.str().c_str() , maptab1, IntTab((i*Y_MAX+j) ,0), PACKET_LENGTH, rho_a, 100, X_MAX, Y_MAX, rho_b, 0, X_MAX, 0, Y_MAX); 

#if STAGE==1
			else
			    new(&initiator_c1[Y_MAX*i+j]) soclib::caba::VciSyntheticInitiator<vci_param> (str1.str().c_str() , maptab1, IntTab((i*Y_MAX+j) ,0), PACKET_LENGTH, rho_a, 100, X_MAX, Y_MAX, 0, 0, X_MAX, 0, Y_MAX); 
#endif
		}

	soclib::caba::VciSyntheticTarget<vci_param> * target_c0 = (soclib::caba::VciSyntheticTarget<vci_param> *) malloc(sizeof(soclib::caba::VciSyntheticTarget<vci_param>) * N_CLUSTERS);
	soclib::caba::VciSyntheticTarget<vci_param> * target_c1 = (soclib::caba::VciSyntheticTarget<vci_param> *) malloc(sizeof(soclib::caba::VciSyntheticTarget<vci_param>) * N_CLUSTERS);
	for(int i = 0 ; i < X_MAX ; i++)
		for(int j = 0 ; j < Y_MAX ; j++){
			std::ostringstream	str0;
			std::ostringstream	str1;
			str0 << "Ram_c0_" << (i*Y_MAX+j) ;
			str1 << "Ram_c1_" << (i*Y_MAX+j) ;
			new(&target_c0[Y_MAX*i+j]) soclib::caba::VciSyntheticTarget<vci_param> (str0.str().c_str() , IntTab(i*Y_MAX+j,0), maptab0, soclib::common::Loader(), 0);
			new(&target_c1[Y_MAX*i+j]) soclib::caba::VciSyntheticTarget<vci_param> (str1.str().c_str() , IntTab(i*Y_MAX+j,0), maptab1, soclib::common::Loader(), 0);
		}

	///////////////////////////////////////////////////////////////
	// Connection of Synthetic Initiator to each local ring per cluster
	///////////////////////////////////////////////////////////////
	for(int i = 0 ; i < N_CLUSTERS ; i++){
	  local_ring_c0[i].p_clk(signal_clk);
	  local_ring_c0[i].p_resetn(signal_resetn);
	  local_ring_c0[i].p_to_initiator[0](signal_vci_ini_synth_c0[0][i]);
	  local_ring_c0[i].p_to_target[0](signal_vci_ini_synth_c0[1][i]);
	  initiator_c0[i].p_clk(signal_clk);
	  initiator_c0[i].p_resetn(signal_resetn);
	  initiator_c0[i].p_vci(signal_vci_ini_synth_c0[0][i]);
	  target_c0[i].p_clk(signal_clk);
	  target_c0[i].p_resetn(signal_resetn);
	  target_c0[i].p_vci(signal_vci_ini_synth_c0[1][i]);
	  local_ring_c1[i].p_clk(signal_clk);
	  local_ring_c1[i].p_resetn(signal_resetn);
	  local_ring_c1[i].p_to_initiator[0](signal_vci_ini_synth_c1[0][i]);
	  local_ring_c1[i].p_to_target[0](signal_vci_ini_synth_c1[1][i]);
	  initiator_c1[i].p_clk(signal_clk);
	  initiator_c1[i].p_resetn(signal_resetn);
	  initiator_c1[i].p_vci(signal_vci_ini_synth_c1[0][i]);
	  target_c1[i].p_clk(signal_clk);
	  target_c1[i].p_resetn(signal_resetn);
	  target_c1[i].p_vci(signal_vci_ini_synth_c1[1][i]);
	}
	
	///////////////////////////////////////////////////////////////
	// Connection of each VDspin Router to each local ring and 
	// neighbors VDspin Router
	///////////////////////////////////////////////////////////////
	for(int i = 0; i < X_MAX ; i++){
	  for(int j = 0; j < Y_MAX ; j++){
	    routers_cmd[i][j].p_clk(signal_clk);
	    routers_cmd[i][j].p_resetn(signal_resetn);
	    routers_rsp[i][j].p_clk(signal_clk);
	    routers_rsp[i][j].p_resetn(signal_resetn);
	    local_ring_c0[i*Y_MAX+j].p_gate_cmd_in( dspin_signals_cmd_c0[0][i][j][LOCAL]);
	    local_ring_c1[i*Y_MAX+j].p_gate_cmd_in( dspin_signals_cmd_c1[0][i][j][LOCAL]);
	    local_ring_c0[i*Y_MAX+j].p_gate_cmd_out(dspin_signals_cmd_c0[1][i][j][LOCAL]);
	    local_ring_c1[i*Y_MAX+j].p_gate_cmd_out(dspin_signals_cmd_c1[1][i][j][LOCAL]);
	    local_ring_c0[i*Y_MAX+j].p_gate_rsp_in( dspin_signals_rsp_c0[0][i][j][LOCAL]);
	    local_ring_c1[i*Y_MAX+j].p_gate_rsp_in( dspin_signals_rsp_c1[0][i][j][LOCAL]);
	    local_ring_c0[i*Y_MAX+j].p_gate_rsp_out(dspin_signals_rsp_c0[1][i][j][LOCAL]);
	    local_ring_c1[i*Y_MAX+j].p_gate_rsp_out(dspin_signals_rsp_c1[1][i][j][LOCAL]);
	    for(int k = 0; k < 5; k++){
	     	if(j == 0){
	     	  if(i == 0){
	     	    routers_cmd[i][j].p_out[0][k](dspin_signals_cmd_c0[0][i][j][k]);
	     	    routers_cmd[i][j].p_out[1][k](dspin_signals_cmd_c1[0][i][j][k]);
	     	    routers_cmd[i][j].p_in[0][k](dspin_signals_cmd_c0[1][i][j][k]);
	     	    routers_cmd[i][j].p_in[1][k](dspin_signals_cmd_c1[1][i][j][k]);
	     	    routers_rsp[i][j].p_out[0][k](dspin_signals_rsp_c0[0][i][j][k]);
	     	    routers_rsp[i][j].p_out[1][k](dspin_signals_rsp_c1[0][i][j][k]);
	     	    routers_rsp[i][j].p_in[0][k](dspin_signals_rsp_c0[1][i][j][k]);
	     	    routers_rsp[i][j].p_in[1][k](dspin_signals_rsp_c1[1][i][j][k]);
	     	  } else {
	     	    if(k == WEST){
	     	   	routers_cmd[i][j].p_out[0][k](dspin_signals_cmd_c0[1][i-1][j][EAST]);
	     	   	routers_cmd[i][j].p_out[1][k](dspin_signals_cmd_c1[1][i-1][j][EAST]);
	     	   	routers_cmd[i][j].p_in[0][k](dspin_signals_cmd_c0[0][i-1][j][EAST]);
	     	   	routers_cmd[i][j].p_in[1][k](dspin_signals_cmd_c1[0][i-1][j][EAST]);
	     	   	routers_rsp[i][j].p_out[0][k](dspin_signals_rsp_c0[1][i-1][j][EAST]);
	     	   	routers_rsp[i][j].p_out[1][k](dspin_signals_rsp_c1[1][i-1][j][EAST]);
	     	   	routers_rsp[i][j].p_in[0][k](dspin_signals_rsp_c0[0][i-1][j][EAST]);
	     	   	routers_rsp[i][j].p_in[1][k](dspin_signals_rsp_c1[0][i-1][j][EAST]);
	     	    } else {
	     	   	routers_cmd[i][j].p_out[0][k](dspin_signals_cmd_c0[0][i][j][k]);
	     	   	routers_cmd[i][j].p_out[1][k](dspin_signals_cmd_c1[0][i][j][k]);
	     	   	routers_cmd[i][j].p_in[0][k](dspin_signals_cmd_c0[1][i][j][k]);
	     	   	routers_cmd[i][j].p_in[1][k](dspin_signals_cmd_c1[1][i][j][k]);
	     	   	routers_rsp[i][j].p_out[0][k](dspin_signals_rsp_c0[0][i][j][k]);
	     	   	routers_rsp[i][j].p_out[1][k](dspin_signals_rsp_c1[0][i][j][k]);
	     	   	routers_rsp[i][j].p_in[0][k](dspin_signals_rsp_c0[1][i][j][k]);
	     	   	routers_rsp[i][j].p_in[1][k](dspin_signals_rsp_c1[1][i][j][k]);
	     	    }
	     	  }
	     	} else {
	     	  if(k == SOUTH){
	     	   	routers_cmd[i][j].p_out[0][k](dspin_signals_cmd_c0[1][i][j-1][NORTH]);
	     	   	routers_cmd[i][j].p_out[1][k](dspin_signals_cmd_c1[1][i][j-1][NORTH]);
	     	   	routers_cmd[i][j].p_in[0][k](dspin_signals_cmd_c0[0][i][j-1][NORTH]);
	     	   	routers_cmd[i][j].p_in[1][k](dspin_signals_cmd_c1[0][i][j-1][NORTH]);
	     	   	routers_rsp[i][j].p_out[0][k](dspin_signals_rsp_c0[1][i][j-1][NORTH]);
	     	   	routers_rsp[i][j].p_out[1][k](dspin_signals_rsp_c1[1][i][j-1][NORTH]);
	     	   	routers_rsp[i][j].p_in[0][k](dspin_signals_rsp_c0[0][i][j-1][NORTH]);
	     	   	routers_rsp[i][j].p_in[1][k](dspin_signals_rsp_c1[0][i][j-1][NORTH]);
	     	  } else if(k == WEST){
	     	     if(i == 0){
	     	   	routers_cmd[i][j].p_out[0][k](dspin_signals_cmd_c0[0][i][j][k]);
	     	   	routers_cmd[i][j].p_out[1][k](dspin_signals_cmd_c1[0][i][j][k]);
	     	   	routers_cmd[i][j].p_in[0][k](dspin_signals_cmd_c0[1][i][j][k]);
	     	   	routers_cmd[i][j].p_in[1][k](dspin_signals_cmd_c1[1][i][j][k]);
	     	   	routers_rsp[i][j].p_out[0][k](dspin_signals_rsp_c0[0][i][j][k]);
	     	   	routers_rsp[i][j].p_out[1][k](dspin_signals_rsp_c1[0][i][j][k]);
	     	   	routers_rsp[i][j].p_in[0][k](dspin_signals_rsp_c0[1][i][j][k]);
	     	   	routers_rsp[i][j].p_in[1][k](dspin_signals_rsp_c1[1][i][j][k]);
	     	     } else {
	     	   	routers_cmd[i][j].p_out[0][k](dspin_signals_cmd_c0[1][i-1][j][EAST]);
	     	   	routers_cmd[i][j].p_out[1][k](dspin_signals_cmd_c1[1][i-1][j][EAST]);
	     	   	routers_cmd[i][j].p_in[0][k](dspin_signals_cmd_c0[0][i-1][j][EAST]);
	     	   	routers_cmd[i][j].p_in[1][k](dspin_signals_cmd_c1[0][i-1][j][EAST]);
	     	   	routers_rsp[i][j].p_out[0][k](dspin_signals_rsp_c0[1][i-1][j][EAST]);
	     	   	routers_rsp[i][j].p_out[1][k](dspin_signals_rsp_c1[1][i-1][j][EAST]);
	     	   	routers_rsp[i][j].p_in[0][k](dspin_signals_rsp_c0[0][i-1][j][EAST]);
	     	   	routers_rsp[i][j].p_in[1][k](dspin_signals_rsp_c1[0][i-1][j][EAST]);
	     	     }
	     	  } else {
	     	   	routers_cmd[i][j].p_out[0][k](dspin_signals_cmd_c0[0][i][j][k]);
	     	   	routers_cmd[i][j].p_out[1][k](dspin_signals_cmd_c1[0][i][j][k]);
	     	   	routers_cmd[i][j].p_in[0][k](dspin_signals_cmd_c0[1][i][j][k]);
	     	   	routers_cmd[i][j].p_in[1][k](dspin_signals_cmd_c1[1][i][j][k]);
	     	   	routers_rsp[i][j].p_out[0][k](dspin_signals_rsp_c0[0][i][j][k]);
	     	   	routers_rsp[i][j].p_out[1][k](dspin_signals_rsp_c1[0][i][j][k]);
	     	   	routers_rsp[i][j].p_in[0][k](dspin_signals_rsp_c0[1][i][j][k]);
	     	   	routers_rsp[i][j].p_in[1][k](dspin_signals_rsp_c1[1][i][j][k]);
	     	  }
	     	}
	    }
	  }
	}

	////////////////////////////////////////////////
	//             Simulation Loop                //
	////////////////////////////////////////////////


	sc_start(sc_core::sc_time(0, SC_NS));
	signal_resetn = false;

	for(int i = 0; i < X_MAX ; i++){
		for(int j = 0; j < Y_MAX ; j++){
			if(j == 0){
			  	dspin_signals_cmd_c0[0][i][j][SOUTH].read = true   ;
			  	dspin_signals_cmd_c0[1][i][j][SOUTH].write = false ;
			  	dspin_signals_cmd_c1[0][i][j][SOUTH].read = true   ;
			  	dspin_signals_cmd_c1[1][i][j][SOUTH].write = false ;
			  	dspin_signals_rsp_c0[0][i][j][SOUTH].read = true   ;
			  	dspin_signals_rsp_c0[1][i][j][SOUTH].write = false ;
			  	dspin_signals_rsp_c1[0][i][j][SOUTH].read = true   ;
			  	dspin_signals_rsp_c1[1][i][j][SOUTH].write = false ;
			} 
			if(j == Y_MAX-1){
			  	dspin_signals_cmd_c0[0][i][j][NORTH].read = true   ;
			  	dspin_signals_cmd_c0[1][i][j][NORTH].write = false ;
			  	dspin_signals_cmd_c1[0][i][j][NORTH].read = true   ;
			  	dspin_signals_cmd_c1[1][i][j][NORTH].write = false ;
			  	dspin_signals_rsp_c0[0][i][j][NORTH].read = true   ;
			  	dspin_signals_rsp_c0[1][i][j][NORTH].write = false ;
			  	dspin_signals_rsp_c1[0][i][j][NORTH].read = true   ;
			  	dspin_signals_rsp_c1[1][i][j][NORTH].write = false ;
			} 
			if(i == 0){
				dspin_signals_cmd_c0[0][i][j][WEST].read = true   ;
				dspin_signals_cmd_c0[1][i][j][WEST].write = false ;
				dspin_signals_cmd_c1[0][i][j][WEST].read = true   ;
				dspin_signals_cmd_c1[1][i][j][WEST].write = false ;
				dspin_signals_rsp_c0[0][i][j][WEST].read = true   ;
				dspin_signals_rsp_c0[1][i][j][WEST].write = false ;
				dspin_signals_rsp_c1[0][i][j][WEST].read = true   ;
				dspin_signals_rsp_c1[1][i][j][WEST].write = false ;
			} 
			if(i == X_MAX-1){
				dspin_signals_cmd_c0[0][i][j][EAST].read = true   ;
				dspin_signals_cmd_c0[1][i][j][EAST].write = false ;
				dspin_signals_cmd_c1[0][i][j][EAST].read = true   ;
				dspin_signals_cmd_c1[1][i][j][EAST].write = false ;
				dspin_signals_rsp_c0[0][i][j][EAST].read = true   ;
				dspin_signals_rsp_c0[1][i][j][EAST].write = false ;
				dspin_signals_rsp_c1[0][i][j][EAST].read = true   ;
				dspin_signals_rsp_c1[1][i][j][EAST].write = false ;
			}
		}
	} 

	sc_start(sc_core::sc_time(1, SC_NS));
	signal_resetn = true;

	for(int t = 0; t < ncycles; t++){
		sc_start(sc_time(1, SC_NS));
		//initiator_c1[4].print_trace();
		//local_ring_c1[4].print_trace();
		//target_c1[4].print_trace();
#if defined(DEBUG) 
		for(int i = 0 ; i < Y_MAX ; i++){
			for(int j = 0 ; j < X_MAX ; j++){
#endif
#if DEBUG==1
				//initiator_c0[i*Y_MAX+j].print_trace();
				//std::cout << std::hex;
				//std::cout << "synt_cmdval  = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].cmdval.read() << std::endl;
				//std::cout << "synt_cmdack  = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].cmdack.read() << std::endl;
				//std::cout << "synt_address = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].address.read() << std::endl;
				//std::cout << "synt_cmd     = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].cmd.read() << std::endl;
				//std::cout << "synt_srcid   = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].srcid.read() << std::endl;
				//std::cout << "synt_trdid   = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].trdid.read() << std::endl;
				//std::cout << "synt_plen    = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].plen.read() << std::endl;
				//std::cout << "synt_eop     = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].eop.read() << std::endl;
				//std::cout << "synt_rspval  = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].rspval.read() << std::endl;
				//std::cout << "synt_rspack  = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].rspack.read() << std::endl;
				//std::cout << "synt_rsrcid  = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].rsrcid.read() << std::endl;
				//std::cout << "synt_rtrdid  = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].rtrdid.read() << std::endl;
				//std::cout << "synt_rpktid  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].rpktid.read() << std::endl;
				//std::cout << "synt_rerror  = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].rerror.read() << std::endl;
				//std::cout << "synt_reop    = " << signal_vci_ini_synth_c0[0][i*Y_MAX+j].reop.read() << std::endl;
				//target_c0[i*Y_MAX+j].print_trace();
				//std::cout << std::hex;
				//std::cout << "target_cmdval  = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].cmdval.read() << std::endl;
				//std::cout << "target_address = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].address.read() << std::endl;
				//std::cout << "target_cmd     = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].cmd.read() << std::endl;
				//std::cout << "target_srcid   = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].srcid.read() << std::endl;
				//std::cout << "target_trdid   = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].trdid.read() << std::endl;
				//std::cout << "target_plen    = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].plen.read() << std::endl;
				//std::cout << "target_eop     = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].eop.read() << std::endl;
				//std::cout << "target_rspval  = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].rspval.read() << std::endl;
				//std::cout << "target_rspack  = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].rspack.read() << std::endl;
				//std::cout << "target_rsrcid  = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].rsrcid.read() << std::endl;
				//std::cout << "target_rtrdid  = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].rtrdid.read() << std::endl;
				//std::cout << "target_rerror  = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].rerror.read() << std::endl;
				//std::cout << "target_reop    = " << signal_vci_ini_synth_c0[1][i*Y_MAX+j].reop.read() << std::endl;
				//initiator_c1[i*Y_MAX+j].print_trace();
				//std::cout << std::hex;
				//std::cout << "synt_cmdval  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].cmdval.read() << std::endl;
				//std::cout << "synt_cmdack  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].cmdack.read() << std::endl;
				//std::cout << "synt_address = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].address.read() << std::endl;
				//std::cout << "synt_cmd     = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].cmd.read() << std::endl;
				//std::cout << "synt_srcid   = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].srcid.read() << std::endl;
				//std::cout << "synt_trdid   = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].trdid.read() << std::endl;
				//std::cout << "synt_pktid   = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].pktid.read() << std::endl;
				//std::cout << "synt_plen    = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].plen.read() << std::endl;
				//std::cout << "synt_eop     = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].eop.read() << std::endl;
				//std::cout << "synt_rspval  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].rspval.read() << std::endl;
				//std::cout << "synt_rspack  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].rspack.read() << std::endl;
				//std::cout << "synt_rsrcid  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].rsrcid.read() << std::endl;
				//std::cout << "synt_rtrdid  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].rtrdid.read() << std::endl;
				//std::cout << "synt_rpktid  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].rpktid.read() << std::endl;
				//std::cout << "synt_rerror  = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].rerror.read() << std::endl;
				//std::cout << "synt_reop    = " << signal_vci_ini_synth_c1[0][i*Y_MAX+j].reop.read() << std::endl;
				target_c1[i*Y_MAX+j].print_trace();
				std::cout << std::hex;
				std::cout << "target_cmdval  = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].cmdval.read() << std::endl;
				std::cout << "target_address = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].address.read() << std::endl;
				std::cout << "target_cmd     = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].cmd.read() << std::endl;
				std::cout << "target_srcid   = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].srcid.read() << std::endl;
				std::cout << "target_trdid   = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].trdid.read() << std::endl;
				std::cout << "target_pktid   = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].pktid.read() << std::endl;
				std::cout << "target_plen    = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].plen.read() << std::endl;
				std::cout << "target_eop     = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].eop.read() << std::endl;
				std::cout << "target_rspval  = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].rspval.read() << std::endl;
				std::cout << "target_rspack  = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].rspack.read() << std::endl;
				std::cout << "target_rsrcid  = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].rsrcid.read() << std::endl;
				std::cout << "target_rtrdid  = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].rtrdid.read() << std::endl;
				std::cout << "target_rpktid  = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].rpktid.read() << std::endl;
				std::cout << "target_rerror  = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].rerror.read() << std::endl;
				std::cout << "target_reop    = " << signal_vci_ini_synth_c1[1][i*Y_MAX+j].reop.read() << std::endl;
#endif
#if DEBUG==2
				local_ring_c0[i*Y_MAX+j].print_trace();
				routers_cmd[i][j].print_trace(0);
				std::cout << std::dec << t << " ns" << std::endl;
				routers_rsp[i][j].print_trace(0);
#endif
#ifdef DEBUG
			}
		}
#endif
				//initiator_c1[4].print_trace();
				//std::cout << std::hex;
				//std::cout << "synt_cmdval  = " << signal_vci_ini_synth_c1[0][255].cmdval.read() << std::endl;
				//std::cout << "synt_cmdack  = " << signal_vci_ini_synth_c1[0][255].cmdack.read() << std::endl;
				//std::cout << "synt_address = " << signal_vci_ini_synth_c1[0][255].address.read() << std::endl;
				//std::cout << "synt_cmd     = " << signal_vci_ini_synth_c1[0][255].cmd.read() << std::endl;
				//std::cout << "synt_srcid   = " << signal_vci_ini_synth_c1[0][255].srcid.read() << std::endl;
				//std::cout << "synt_trdid   = " << signal_vci_ini_synth_c1[0][255].trdid.read() << std::endl;
				//std::cout << "synt_pktid   = " << signal_vci_ini_synth_c1[0][255].pktid.read() << std::endl;
				//std::cout << "synt_plen    = " << signal_vci_ini_synth_c1[0][255].plen.read() << std::endl;
				//std::cout << "synt_eop     = " << signal_vci_ini_synth_c1[0][255].eop.read() << std::endl;
				//std::cout << "synt_rspval  = " << signal_vci_ini_synth_c1[0][255].rspval.read() << std::endl;
				//std::cout << "synt_rspack  = " << signal_vci_ini_synth_c1[0][255].rspack.read() << std::endl;
				//std::cout << "synt_rsrcid  = " << signal_vci_ini_synth_c1[0][255].rsrcid.read() << std::endl;
				//std::cout << "synt_rtrdid  = " << signal_vci_ini_synth_c1[0][255].rtrdid.read() << std::endl;
				//std::cout << "synt_rpktid  = " << signal_vci_ini_synth_c1[0][255].rpktid.read() << std::endl;
				//std::cout << "synt_rerror  = " << signal_vci_ini_synth_c1[0][255].rerror.read() << std::endl;
				//std::cout << "synt_reop    = " << signal_vci_ini_synth_c1[0][255].reop.read() << std::endl;
				//target_c1[4].print_trace();
				//std::cout << std::hex;
				//std::cout << "target_cmdval  = " << signal_vci_ini_synth_c1[1][4].cmdval.read() << std::endl;
				//std::cout << "target_address = " << signal_vci_ini_synth_c1[1][4].address.read() << std::endl;
				//std::cout << "target_cmd     = " << signal_vci_ini_synth_c1[1][4].cmd.read() << std::endl;
				//std::cout << "target_srcid   = " << signal_vci_ini_synth_c1[1][4].srcid.read() << std::endl;
				//std::cout << "target_trdid   = " << signal_vci_ini_synth_c1[1][4].trdid.read() << std::endl;
				//std::cout << "target_pktid   = " << signal_vci_ini_synth_c1[1][4].pktid.read() << std::endl;
				//std::cout << "target_plen    = " << signal_vci_ini_synth_c1[1][4].plen.read() << std::endl;
				//std::cout << "target_eop     = " << signal_vci_ini_synth_c1[1][4].eop.read() << std::endl;
				//std::cout << "target_rspval  = " << signal_vci_ini_synth_c1[1][4].rspval.read() << std::endl;
				//std::cout << "target_rspack  = " << signal_vci_ini_synth_c1[1][4].rspack.read() << std::endl;
				//std::cout << "target_rsrcid  = " << signal_vci_ini_synth_c1[1][4].rsrcid.read() << std::endl;
				//std::cout << "target_rtrdid  = " << signal_vci_ini_synth_c1[1][4].rtrdid.read() << std::endl;
				//std::cout << "target_rpktid  = " << signal_vci_ini_synth_c1[1][4].rpktid.read() << std::endl;
				//std::cout << "target_rerror  = " << signal_vci_ini_synth_c1[1][4].rerror.read() << std::endl;
				//std::cout << "target_reop    = " << signal_vci_ini_synth_c1[1][4].reop.read() << std::endl;
			
			//for(int i = 0 ; i < Y_MAX ; i++){
			//	for(int j = 0 ; j < X_MAX ; j++){
			//		std::cout << std::dec << t << " cycles " << std::endl;
			//		local_ring_c1[i*Y_MAX+j].print_trace();
			//		//initiator_c1[i*Y_MAX+j].print_trace();
			//	}
			//}
			//initiator_c1[4].print_trace();
			//std::cout << std::hex;
			//std::cout << "synt_cmdval  = " << signal_vci_ini_synth_c1[0][4].cmdval.read() << std::endl;
			//std::cout << "synt_cmdack  = " << signal_vci_ini_synth_c1[0][4].cmdack.read() << std::endl;
			//std::cout << "synt_address = " << signal_vci_ini_synth_c1[0][4].address.read() << std::endl;
			//std::cout << "synt_cmd     = " << signal_vci_ini_synth_c1[0][4].cmd.read() << std::endl;
			//std::cout << "synt_srcid   = " << signal_vci_ini_synth_c1[0][4].srcid.read() << std::endl;
			//std::cout << "synt_trdid   = " << signal_vci_ini_synth_c1[0][4].trdid.read() << std::endl;
			//std::cout << "synt_pktid   = " << signal_vci_ini_synth_c1[0][4].pktid.read() << std::endl;
			//std::cout << "synt_plen    = " << signal_vci_ini_synth_c1[0][4].plen.read() << std::endl;
			//std::cout << "synt_eop     = " << signal_vci_ini_synth_c1[0][4].eop.read() << std::endl;
			//std::cout << "synt_rspval  = " << signal_vci_ini_synth_c1[0][4].rspval.read() << std::endl;
			//std::cout << "synt_rspack  = " << signal_vci_ini_synth_c1[0][4].rspack.read() << std::endl;
			//std::cout << "synt_rsrcid  = " << signal_vci_ini_synth_c1[0][4].rsrcid.read() << std::endl;
			//std::cout << "synt_rtrdid  = " << signal_vci_ini_synth_c1[0][4].rtrdid.read() << std::endl;
			//std::cout << "synt_rpktid  = " << signal_vci_ini_synth_c1[0][4].rpktid.read() << std::endl;
			//std::cout << "synt_rerror  = " << signal_vci_ini_synth_c1[0][4].rerror.read() << std::endl;
			//std::cout << "synt_reop    = " << signal_vci_ini_synth_c1[0][4].reop.read() << std::endl;
			//local_ring_c1[4].print_trace();
			//initiator_c1[27].print_fifo_state();
			//if (!(t%1000000))
			//	std::cout <<std::dec << t << " 1000000 cycles passed" << std::endl;


	}

	//double latency_c0 = 0;
	double latency_c1 = 0;
	double latency_bc = 0;
	std::cout << "Results : " << std::endl;
	for(int i = 0 ; i < Y_MAX ; i++){
		for(int j = 0 ; j < X_MAX ; j++){
			//initiator_c0[i*Y_MAX+j].printStats();
			//latency_c0 += initiator_c0[i*Y_MAX+j].getLatencySingle() ;
			initiator_c1[i*Y_MAX+j].printStats();
			latency_c1 += initiator_c1[i*Y_MAX+j].getLatencySingle() ;
			latency_bc += initiator_c1[i*Y_MAX+j].getLatencyBC();
			std::cout << "bc latency " << latency_bc << std::endl;
		}
	}

		
	//std::cout << "Latency_c0 : " << latency_c0 << std::endl;
	std::cout << "Latency_c1 : " << latency_c1 << std::endl;
	std::cout << "BC latency : " << latency_bc << std::endl;

	std::cout << "Simulation Ends" << std::endl;


	return EXIT_SUCCESS;
}

int sc_main (int argc, char *argv[])
{
	try {
		return _main(argc, argv);
	} catch (std::exception &e) {
		std::cout << e.what() << std::endl;
	} catch (...) {
		std::cout << "Unknown exception occured" << std::endl;
		throw;
	}
	return 1;
}

