#define yes 1
#define no  0

#define USE_RING       no
#define USE_TSAR_V3    yes
#define SECTOR_SIZE    4096

#define L1_WAYS        4
#define L1_SETS        64

#define MEMC_WAYS      16
#define MEMC_SETS      256

#define MEMC_HEAP      1024 //4096

#define XRAM_LATENCY   0

#define USE_VCI_LOGGER_ON_L1_CPU0  no
#define USE_VCI_LOGGER_ON_L1_CPU1  no
#define USE_VCI_LOGGER_ON_L1_CPU2  no
#define USE_VCI_LOGGER_ON_L1_CPU3  no

#define USE_VCI_LOGGER_ON_ROM      no

#define USE_VCI_PROFILER_ON_CPU0   yes
#define USE_VCI_PROFILER_ON_CPU1   yes
#define USE_VCI_PROFILER_ON_CPU2   yes
#define USE_VCI_PROFILER_ON_CPU3   yes

#define USE_VCI_PROFILER (USE_VCI_PROFILER_ON_CPU0 || USE_VCI_PROFILER_ON_CPU1 || USE_VCI_PROFILER_ON_CPU2 || USE_VCI_PROFILER_ON_CPU3)

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

#include "mapping_table.h"
#include "mips32.h"
#include "vci_simple_ram.h"
#include "vci_multi_tty.h"

#if USE_RING
#include "vci_simple_ring_fast.h"
#else
#include "vci_vgmn.h"
#endif

#if USE_VCI_PROFILER
#include "vci_profiler.h"
#endif


#if USE_TSAR_V3
#include "vci_mem_cache_v3.h"
#else
#include "vci_mem_cache_v2.h"
#endif

#include "vci_cc_vcache_wrapper2_v1.h"
#include "vci_logger.h"
#include "vci_xicu.h"
#include "vci_framebuffer.h"
#include "vci_dma_tsar_v2.h"
#include "vci_block_device_tsar_v2.h"

#ifdef USE_GDB_SERVER
#include "iss/gdbserver.h"
#endif

//#define  VCI_LOGGER_ON_L1
//#define  VCI_LOGGER_ON_ROM
//#define VCI_LOGGER_ON_L1_TGT

#define _TO_STR(x) #x
#define TO_STR(x) _TO_STR(x)

#include "segmentation.h"

#if  !(defined(KERNEL_BIN_IMG) || defined(BOOT_INFO_BLOCK))
#error KERNEL_BIN_IMG or BOOT_INFO_BLOCK macros definition are missed
#endif 

#include <config.h>


static const struct option opts[] = {{"XFB",    required_argument, NULL, 'x'},
				     {"YFB",    required_argument, NULL, 'y'},
				     {"FBMODE", required_argument, NULL, 'm'},
				     {"SSTEP",  required_argument, NULL, 's'},
				     {"LOGMC0", required_argument, NULL, 'l'},
				     {"BLKSZ",  required_argument, NULL, 'b'},
				     {"HELP",   no_argument,       NULL, 'h'},
				     {NULL,     no_argument,       NULL,  0}};

int _main(int argc, char *argv[])
{
	uint64_t       ms1, ms2;
	struct timeval t1, t2;
	uint64_t     sstep    = 10000000000ULL;
	uint64_t     ncycles  = 10000000000ULL;
	size_t       xfb      = FB_XSIZE;
	size_t       yfb      = FB_YSIZE;
	size_t       fb_mode  = 420;
	size_t       blksz    = SECTOR_SIZE;
	int          longIndex;
	int          c;
	bool         do_loggerMc0 = false;

	using namespace sc_core;
	// Avoid repeating these everywhere
	using soclib::common::IntTab;
	using soclib::common::Segment;

	// Define VCI parameters
	typedef soclib::caba::VciParams<4,8,32,1,1,1,8,4,4,1> vci_param;
	typedef soclib::common::Mips32ElIss proc_iss;
	// Mapping table

	while ((c = getopt_long(argc, argv, "x:y:s:m:l:b:h", opts, &longIndex)) != -1) 
	{
	  switch(c) 
	  {
	  case 'x':
	    xfb = atoi(optarg);
	    break;

	  case 'y':
	    yfb = atoi(optarg); 
	    break;

	  case 'm':
	    fb_mode = atoi(optarg);
	    break;

	  case 's':
	    sstep = atoll(optarg);
	    break;

	  case 'l':
	    if(strcmp(optarg, "ON") == 0)
	      do_loggerMc0 = true;
	    break;

	  case 'b':
	    blksz = atoi(optarg);
	    break;
      
	  case 'h':
	    std::cout << "Usage: "<< argv[0] << " <options>" << std::endl << std::endl;
	    std::cout << "Options:" << std::endl;
	    std::cout << "  --XFB     : FrameBuffer XSIZE" << std::endl;
	    std::cout << "  --YFB     : FrameBuffer YSIZE" << std::endl;
	    std::cout << "  --FBMODE  : FrameBuffer MODE {YUV:420, YUV:422, RGB:0, RGB:16, RGB:32, RGBPAL:256}" << std::endl;
	    std::cout << "  --SSTEP   : Statistics period" << std::endl;
	    std::cout << "  --LOGMC0  : {ON|OFF} Trace the charge of directe network input of MemCache0" << std::endl;
	    std::cout << "  --BLKSZ   : Sector Size (in bytes)" << std::endl;
	    std::cout << "  --HELP    : Print out command line options" << std::endl << std::endl;
	    std::cout << "Default: "  << argv[0] 
		      << " --XFB "    << xfb 
		      << " --YFB "    << yfb 
		      << " --FBMODE " << fb_mode
		      << " --SSTEP "  << sstep 
		      << " --LOGMC0 " << "OFF"
		      << " --BLKSZ "  << blksz
		      << std::endl;
	    exit(0);
	    break;
	  }
	}

	std::cout << "CONFIG_MEMC_UPDATE_TAB_LINES = " << CONFIG_MEMC_UPDATE_TAB_LINES << std::endl;

	soclib::common::MappingTable maptabp(32, IntTab(8), IntTab(8), 0xF0000000);
	
	maptabp.add(Segment("mc_m" , RAM_BASE , RAM_SIZE , IntTab(0), true));
	maptabp.add(Segment("rom", ROM_BASE, ROM_SIZE, IntTab(1), true));

	maptabp.add(Segment("bd", BD_BASE, BD_SIZE, IntTab(2), false));
	maptabp.add(Segment("tty"  , TTY_BASE  , TTY_SIZE  , IntTab(3), false));
	maptabp.add(Segment("xicu" , XICU_BASE , XICU_SIZE , IntTab(4), false));
	maptabp.add(Segment("dma", DMA_BASE, DMA_SIZE, IntTab(5), false));
	maptabp.add(Segment("fb", FB_BASE, FB_SIZE, IntTab(6), false));

	std::cout << maptabp << std::endl;

        soclib::common::MappingTable maptabc(32, IntTab(8), IntTab(8), 0xF0000000);
	maptabc.add(Segment("c_proc0" , PROC0_BASE , PROC0_SIZE , IntTab(0), false, true, IntTab(0)));
	maptabc.add(Segment("c_proc1" , PROC1_BASE , PROC1_SIZE , IntTab(1), false, true, IntTab(1)));
	maptabc.add(Segment("c_proc2" , PROC2_BASE , PROC2_SIZE , IntTab(2), false, true, IntTab(2)));
	maptabc.add(Segment("c_proc3" , PROC3_BASE , PROC3_SIZE , IntTab(3), false, true, IntTab(3)));
	maptabc.add(Segment("mc_m" , RAM_BASE , RAM_SIZE , IntTab(4), false ));
	
	maptabc.add(Segment("rom", ROM_BASE, ROM_SIZE, IntTab(4), true));

	std::cout << maptabc << std::endl;
	
	soclib::common::MappingTable maptabx(32, IntTab(8), IntTab(8), 0xF0000000);
	maptabx.add(Segment("xram" , RAM_BASE , RAM_SIZE , IntTab(0), false));
	
	
	std::cout << maptabx << std::endl;

	//soclib::caba::VciLogger<vci_param> vci_logger0("vci_logger_mc0", maptabp, do_loggerMc0);
	
	// Signals

	sc_clock	signal_clk("clk");
	sc_signal<bool> signal_resetn("resetn");
   
	sc_signal<bool> signal_proc0_it0("mips0_it0"); 
	sc_signal<bool> signal_proc0_it1("mips0_it1"); 
	sc_signal<bool> signal_proc0_it2("mips0_it2"); 
	sc_signal<bool> signal_proc0_it3("mips0_it3"); 
	sc_signal<bool> signal_proc0_it4("mips0_it4"); 
	sc_signal<bool> signal_proc0_it5("mips0_it5");

	sc_signal<bool> signal_proc1_it0("mips1_it0"); 
	sc_signal<bool> signal_proc1_it1("mips1_it1"); 
	sc_signal<bool> signal_proc1_it2("mips1_it2"); 
	sc_signal<bool> signal_proc1_it3("mips1_it3"); 
	sc_signal<bool> signal_proc1_it4("mips1_it4"); 
	sc_signal<bool> signal_proc1_it5("mips1_it5");

	sc_signal<bool> signal_proc2_it0("mips2_it0"); 
	sc_signal<bool> signal_proc2_it1("mips2_it1"); 
	sc_signal<bool> signal_proc2_it2("mips2_it2"); 
	sc_signal<bool> signal_proc2_it3("mips2_it3"); 
	sc_signal<bool> signal_proc2_it4("mips2_it4"); 
	sc_signal<bool> signal_proc2_it5("mips2_it5");

	sc_signal<bool> signal_proc3_it0("mips3_it0"); 
	sc_signal<bool> signal_proc3_it1("mips3_it1"); 
	sc_signal<bool> signal_proc3_it2("mips3_it2"); 
	sc_signal<bool> signal_proc3_it3("mips3_it3"); 
	sc_signal<bool> signal_proc3_it4("mips3_it4"); 
	sc_signal<bool> signal_proc3_it5("mips3_it5");

	soclib::caba::VciSignals<vci_param> signal_vci_ini_rw_proc0("vci_ini_rw_proc0");
	soclib::caba::VciSignals<vci_param> signal_vci_ini_c_proc0("vci_ini_c_proc0");
	soclib::caba::VciSignals<vci_param> signal_vci_tgt_proc0("vci_tgt_proc0");

	soclib::caba::VciSignals<vci_param> signal_vci_ini_rw_proc1("vci_ini_rw_proc1");
	soclib::caba::VciSignals<vci_param> signal_vci_ini_c_proc1("vci_ini_c_proc1");
	soclib::caba::VciSignals<vci_param> signal_vci_tgt_proc1("vci_tgt_proc1");

	soclib::caba::VciSignals<vci_param> signal_vci_ini_rw_proc2("vci_ini_rw_proc2");
	soclib::caba::VciSignals<vci_param> signal_vci_ini_c_proc2("vci_ini_c_proc2");
	soclib::caba::VciSignals<vci_param> signal_vci_tgt_proc2("vci_tgt_proc2");

	soclib::caba::VciSignals<vci_param> signal_vci_ini_rw_proc3("vci_ini_rw_proc3");
	soclib::caba::VciSignals<vci_param> signal_vci_ini_c_proc3("vci_ini_c_proc3");
	soclib::caba::VciSignals<vci_param> signal_vci_tgt_proc3("vci_tgt_proc3");

	soclib::caba::VciSignals<vci_param> signal_vci_tty("signal_vci_tty");

	
	soclib::caba::VciSignals<vci_param> signal_vci_xicu("signal_vci_xicu");
	soclib::caba::VciSignals<vci_param> signal_vci_dmai("signal_vci_dmai");
	soclib::caba::VciSignals<vci_param> signal_vci_dmat("signal_vci_dmat");
	soclib::caba::VciSignals<vci_param> signal_vci_vcifb("signal_vci_vcifb");
	soclib::caba::VciSignals<vci_param> signal_vci_vcibd_i("signal_vci_vcibd_i");
	soclib::caba::VciSignals<vci_param> signal_vci_vcibd_t("signal_vci_vcibd_t");
	soclib::caba::VciSignals<vci_param> signal_vci_tgt_rom("vci_tgt_rom");

	soclib::caba::VciSignals<vci_param> signal_vci_tgt_xram("vci_tgt_xram");

	soclib::caba::VciSignals<vci_param> signal_vci_ixr_memc("vci_ixr_memc");
	soclib::caba::VciSignals<vci_param> signal_vci_ini_memc("vci_ini_memc");
	soclib::caba::VciSignals<vci_param> signal_vci_tgt_memc("vci_tgt_memc");
	soclib::caba::VciSignals<vci_param> signal_vci_tgt_cleanup_memc("vci_tgt_cleanup_memc");

	sc_signal<bool> signal_icu_irq0("signal_xicu_irq0");
	sc_signal<bool> signal_icu_irq1("signal_xicu_irq1");
	sc_signal<bool> signal_icu_irq2("signal_xicu_irq2");
	sc_signal<bool> signal_icu_irq3("signal_xicu_irq3");
	sc_signal<bool> signal_icu_irq4("signal_xicu_irq4");
	sc_signal<bool> signal_icu_irq5("signal_xicu_irq5");
	sc_signal<bool> signal_icu_irq6("signal_xicu_irq6");

	
	soclib::common::Loader loader("bootloader.bin",
				      "kernel-soclib.bin@"TO_STR(KERNEL_BIN_IMG)":D",
				      "arch-info.bin@"TO_STR(BOOT_INFO_BLOCK)":D");


        //                                  init_rw   init_c   tgt
	soclib::caba::VciCcVCacheWrapper2V1<vci_param, proc_iss > 
	proc0("proc_0", 0, maptabp, maptabc, IntTab(0),IntTab(0),IntTab(0),
	      4,16,4,16,
	      L1_WAYS,L1_SETS,16,
	      L1_WAYS,L1_SETS,16,
	      16);

	soclib::caba::VciCcVCacheWrapper2V1<vci_param, proc_iss > 
	proc1("proc_1", 1, maptabp, maptabc, IntTab(1),IntTab(1),IntTab(1),
	      4,16,4,16,
	      L1_WAYS,L1_SETS,16,
	      L1_WAYS,L1_SETS,16,
	      16);

	soclib::caba::VciCcVCacheWrapper2V1<vci_param, proc_iss > 
	proc2("proc_2", 2, maptabp, maptabc, IntTab(2),IntTab(2),IntTab(2),
	      4,16,4,16,
	      L1_WAYS,L1_SETS,16,
	      L1_WAYS,L1_SETS,16,
	      16);

	soclib::caba::VciCcVCacheWrapper2V1<vci_param, proc_iss > 
	proc3("proc_3", 3, maptabp, maptabc, IntTab(3),IntTab(3),IntTab(3),
	      4,16,4,16,
	      L1_WAYS,L1_SETS,16,
	      L1_WAYS,L1_SETS,16,
	      16);

	soclib::caba::VciSimpleRam<vci_param> 
	rom("rom", IntTab(1), maptabp, loader);

	soclib::caba::VciSimpleRam<vci_param> 
	  xram("xram", IntTab(0), maptabx, loader, XRAM_LATENCY);

        //                                  x_init    c_init    p_tgt     c_tgt
	
#if USE_TSAR_V3
	soclib::caba::VciMemCacheV3<vci_param> 
	  memc("memc",maptabp,maptabc,maptabx,IntTab(0),IntTab(4),IntTab(0), IntTab(4),MEMC_WAYS,MEMC_SETS,16,MEMC_HEAP);
#else
	soclib::caba::VciMemCacheV2<vci_param> 
	memc("memc",maptabp,maptabc,maptabx,IntTab(0),IntTab(4),IntTab(0), IntTab(4),16,256,16);
#endif
	//memc("memc",maptabp,maptabc,maptabx,IntTab(0),IntTab(4),IntTab(2), IntTab(4),4,16,16,32);
       
	soclib::caba::VciXicu<vci_param> vcixicu("vcixicu", maptabp, IntTab(4), 4 /* npti */, 6 /* nhwi */, 4 /* nwti */, 4 /* nirq */);

	soclib::caba::VciMultiTty<vci_param> vcitty("vcitty",	IntTab(3), maptabp, "tty0" ,"tty1", "tty2", "tty3", NULL);
	soclib::caba::VciDmaTsarV2<vci_param> vcidma("vcidma", maptabp, IntTab(4), IntTab(5), 64);//(1<<(vci_param::K-1))); 

	soclib::caba::VciBlockDeviceTsarV2<vci_param> vcibd("vcitbd", 
							    maptabp, 
							    IntTab(5), 
							    IntTab(2), 
							    "hdd-img.bin", 
							    blksz);

	soclib::caba::VciFrameBuffer<vci_param> vcifb("vcifb", IntTab(6), maptabp, xfb, yfb, fb_mode);
	

#if USE_VCI_LOGGER_ON_L1_CPU0
  soclib::caba::VciLogger<vci_param> vci_logger0("vci_logger0",maptabp);
#endif

#if USE_VCI_LOGGER_ON_CPU1
  soclib::caba::VciLogger<vci_param> vci_logger1("vci_logger1",maptabp);
#endif

#if USE_VCI_LOGGER_ON_CPU2
  soclib::caba::VciLogger<vci_param> vci_logger2("vci_logger2",maptabp);
#endif

#if USE_VCI_LOGGER_ON_CPU3
  soclib::caba::VciLogger<vci_param> vci_logger3("vci_logger3",maptabp);
#endif

#if USE_VCI_LOGGER_ON_ROM
  soclib::caba::VciLogger<vci_param> vci_logger4("vci_logger4",maptabp);
#endif


#if USE_VCI_PROFILER_ON_CPU0
  soclib::caba::VciProfiler<vci_param, proc_iss> vci_prof0("vci_prof0", 0, 0, 0, 1, 1, 32);
#endif

#if USE_VCI_PROFILER_ON_CPU1
  soclib::caba::VciProfiler<vci_param, proc_iss> vci_prof1("vci_prof1", 0, 0, 0, 1, 1, 32);
#endif

#if USE_VCI_PROFILER_ON_CPU2
  soclib::caba::VciProfiler<vci_param, proc_iss> vci_prof2("vci_prof2", 0, 0, 0, 1, 1, 32);
#endif

#if USE_VCI_PROFILER_ON_CPU3
  soclib::caba::VciProfiler<vci_param, proc_iss> vci_prof3("vci_prof3", 0, 0, 0, 1, 1, 32);
#endif

#if USE_RING
  std::cout << "Local Interconnect Type : RING" << std::endl;
	//soclib::caba::VciVgmn<vci_param> 
	soclib::caba::VciSimpleRingFast<vci_param, 40, 33> 
	  ringp("ringp",maptabp, IntTab(), 4, 6, 7);//, /*3*/1, 8);
	
	//soclib::caba::VciVgmn<vci_param> 
	soclib::caba::VciSimpleRingFast<vci_param, 40, 33> 
	  ringc("ringc",maptabc, IntTab(), 4, 5, 5);//, /*2*/1, 8);

#else
	std::cout << "Local Interconnect Type : VGMN" << std::endl;
	soclib::caba::VciVgmn<vci_param> 
	  ringp("ringp",maptabp, 6, 7, 1, 8);
	
	soclib::caba::VciVgmn<vci_param> 
	  ringc("ringc",maptabc, 5, 5, 1, 8);
#endif

	proc0.p_clk(signal_clk);  
	proc0.p_resetn(signal_resetn);  
	proc0.p_irq[0](signal_proc0_it0); 
	proc0.p_irq[1](signal_proc0_it1); 
	proc0.p_irq[2](signal_proc0_it2); 
	proc0.p_irq[3](signal_proc0_it3); 
	proc0.p_irq[4](signal_proc0_it4); 
	proc0.p_irq[5](signal_proc0_it5); 
	proc0.p_vci_ini_rw(signal_vci_ini_rw_proc0);
	proc0.p_vci_ini_c(signal_vci_ini_c_proc0);
	proc0.p_vci_tgt(signal_vci_tgt_proc0);

	proc1.p_clk(signal_clk);  
	proc1.p_resetn(signal_resetn);  
	proc1.p_irq[0](signal_proc1_it0); 
	proc1.p_irq[1](signal_proc1_it1); 
	proc1.p_irq[2](signal_proc1_it2); 
	proc1.p_irq[3](signal_proc1_it3); 
	proc1.p_irq[4](signal_proc1_it4); 
	proc1.p_irq[5](signal_proc1_it5); 
	proc1.p_vci_ini_rw(signal_vci_ini_rw_proc1);
	proc1.p_vci_ini_c(signal_vci_ini_c_proc1);
	proc1.p_vci_tgt(signal_vci_tgt_proc1);

	proc2.p_clk(signal_clk);  
	proc2.p_resetn(signal_resetn);  
	proc2.p_irq[0](signal_proc2_it0); 
	proc2.p_irq[1](signal_proc2_it1); 
	proc2.p_irq[2](signal_proc2_it2); 
	proc2.p_irq[3](signal_proc2_it3); 
	proc2.p_irq[4](signal_proc2_it4); 
	proc2.p_irq[5](signal_proc2_it5); 
	proc2.p_vci_ini_rw(signal_vci_ini_rw_proc2);
	proc2.p_vci_ini_c(signal_vci_ini_c_proc2);
	proc2.p_vci_tgt(signal_vci_tgt_proc2);

	proc3.p_clk(signal_clk);  
	proc3.p_resetn(signal_resetn);  
	proc3.p_irq[0](signal_proc3_it0); 
	proc3.p_irq[1](signal_proc3_it1); 
	proc3.p_irq[2](signal_proc3_it2); 
	proc3.p_irq[3](signal_proc3_it3); 
	proc3.p_irq[4](signal_proc3_it4); 
	proc3.p_irq[5](signal_proc3_it5); 
	proc3.p_vci_ini_rw(signal_vci_ini_rw_proc3);
	proc3.p_vci_ini_c(signal_vci_ini_c_proc3);
	proc3.p_vci_tgt(signal_vci_tgt_proc3);

	rom.p_clk(signal_clk);
	rom.p_resetn(signal_resetn);
	rom.p_vci(signal_vci_tgt_rom);

#if USE_VCI_LOGGER_ON_L1_CPU0
	vci_logger0.p_clk(signal_clk);
	vci_logger0.p_resetn(signal_resetn);
	vci_logger0.p_vci(signal_vci_ini_rw_proc0);
#endif


#if USE_VCI_LOGGER_ON_L1_CPU1
	vci_logger1.p_clk(signal_clk);
	vci_logger1.p_resetn(signal_resetn);
	vci_logger1.p_vci(signal_vci_ini_rw_proc1);
#endif

#if USE_VCI_LOGGER_ON_L1_CPU2
	vci_logger2.p_clk(signal_clk);
	vci_logger2.p_resetn(signal_resetn);
	vci_logger2.p_vci(signal_vci_ini_rw_proc2);
#endif

#if USE_VCI_LOGGER_ON_L1_CPU3
	vci_logger3.p_clk(signal_clk);
	vci_logger3.p_resetn(signal_resetn);
	vci_logger3.p_vci(signal_vci_ini_rw_proc3);
#endif

#if USE_VCI_LOGGER_ON_ROM
	vci_logger4.p_clk(signal_clk);
	vci_logger4.p_resetn(signal_resetn);
	vci_logger4.p_vci(signal_vci_tgt_rom);
#endif


#if USE_VCI_PROFILER_ON_CPU0
	vci_prof0.p_clk(signal_clk);
	vci_prof0.p_resetn(signal_resetn);
	vci_prof0.p_vci(signal_vci_ini_rw_proc0);
	vci_prof0.set_L1_cache(&proc0);
#endif

#if USE_VCI_PROFILER_ON_CPU1
	vci_prof1.p_clk(signal_clk);
	vci_prof1.p_resetn(signal_resetn);
	vci_prof1.p_vci(signal_vci_ini_rw_proc1);
	vci_prof1.set_L1_cache(&proc1);
#endif

#if USE_VCI_PROFILER_ON_CPU2
	vci_prof2.p_clk(signal_clk);
	vci_prof2.p_resetn(signal_resetn);
	vci_prof2.p_vci(signal_vci_ini_rw_proc2);
	vci_prof2.set_L1_cache(&proc2);
#endif

#if USE_VCI_PROFILER_ON_CPU3
	vci_prof3.p_clk(signal_clk);
	vci_prof3.p_resetn(signal_resetn);
	vci_prof3.p_vci(signal_vci_ini_rw_proc3);
	vci_prof3.set_L1_cache(&proc3);
#endif

	vcixicu.p_resetn(signal_resetn);
	vcixicu.p_clk(signal_clk);
	vcixicu.p_vci(signal_vci_xicu);
	vcixicu.p_hwi[0](signal_icu_irq0);
	vcixicu.p_hwi[1](signal_icu_irq1);
	vcixicu.p_hwi[2](signal_icu_irq2);
	vcixicu.p_hwi[3](signal_icu_irq3);
	vcixicu.p_hwi[4](signal_icu_irq4);
	vcixicu.p_hwi[5](signal_icu_irq5);

	vcixicu.p_irq[0](signal_proc0_it0);
	vcixicu.p_irq[1](signal_proc1_it0);
	vcixicu.p_irq[2](signal_proc2_it0);
	vcixicu.p_irq[3](signal_proc3_it0);
	vcidma.p_clk(signal_clk);
	vcidma.p_resetn(signal_resetn);
	vcidma.p_irq(signal_icu_irq4); 

	vcifb.p_clk(signal_clk);
	vcifb.p_resetn(signal_resetn);
	vcifb.p_vci(signal_vci_vcifb);

	vcitty.p_clk(signal_clk);
	vcitty.p_resetn(signal_resetn);
	vcitty.p_vci(signal_vci_tty);
	vcitty.p_irq[0](signal_icu_irq0); 
	vcitty.p_irq[1](signal_icu_irq1); 
	vcitty.p_irq[2](signal_icu_irq2); 
	vcitty.p_irq[3](signal_icu_irq3); 


	vcidma.p_vci_target(signal_vci_dmat);
	vcidma.p_vci_initiator(signal_vci_dmai);
	
	memc.p_clk(signal_clk);
	memc.p_resetn(signal_resetn);
	memc.p_vci_tgt(signal_vci_tgt_memc);
	memc.p_vci_tgt_cleanup(signal_vci_tgt_cleanup_memc);
	memc.p_vci_ini(signal_vci_ini_memc);
	memc.p_vci_ixr(signal_vci_ixr_memc);

	vcibd.p_clk(signal_clk);
	vcibd.p_resetn(signal_resetn);
	vcibd.p_vci_target(signal_vci_vcibd_t);
	vcibd.p_vci_initiator(signal_vci_vcibd_i);
	vcibd.p_irq(signal_icu_irq5);


	xram.p_clk(signal_clk);
	xram.p_resetn(signal_resetn);
	xram.p_vci(signal_vci_ixr_memc);
	

	ringp.p_clk(signal_clk);
	ringp.p_resetn(signal_resetn);

	ringc.p_clk(signal_clk);
	ringc.p_resetn(signal_resetn);

	ringp.p_to_initiator[0](signal_vci_ini_rw_proc0);
	ringp.p_to_initiator[1](signal_vci_ini_rw_proc1);
	ringp.p_to_initiator[2](signal_vci_ini_rw_proc2);
	ringp.p_to_initiator[3](signal_vci_ini_rw_proc3);
	ringp.p_to_initiator[4](signal_vci_dmai);
	ringp.p_to_initiator[5](signal_vci_vcibd_i);
	

	ringc.p_to_initiator[0](signal_vci_ini_c_proc0);
	ringc.p_to_initiator[1](signal_vci_ini_c_proc1);
	ringc.p_to_initiator[2](signal_vci_ini_c_proc2);
	ringc.p_to_initiator[3](signal_vci_ini_c_proc3);
	ringc.p_to_initiator[4](signal_vci_ini_memc);


	ringp.p_to_target[0](signal_vci_tgt_memc);
	ringp.p_to_target[1](signal_vci_tgt_rom);
	ringp.p_to_target[2](signal_vci_vcibd_t);
	ringp.p_to_target[3](signal_vci_tty);
	ringp.p_to_target[4](signal_vci_xicu);
	ringp.p_to_target[5](signal_vci_dmat);
	ringp.p_to_target[6](signal_vci_vcifb);

	ringc.p_to_target[0](signal_vci_tgt_proc0);
	ringc.p_to_target[1](signal_vci_tgt_proc1);
	ringc.p_to_target[2](signal_vci_tgt_proc2);
	ringc.p_to_target[3](signal_vci_tgt_proc3);
	ringc.p_to_target[4](signal_vci_tgt_cleanup_memc);


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

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

	if (gettimeofday(&t1, NULL) != 0) {
	      perror("gettimeofday");
	      return EXIT_FAILURE;
	}
	
	for(uint64_t i=1 ; i<ncycles ; i++)
	{
	  sc_start(sc_core::sc_time(1, SC_NS));
	  
	  if ( (i % sstep) == 0)
	  {
	    memc.print_stats();
	    proc0.print_trace();
	    proc0.print_stats();
	    proc0.clear_stats();
	   
#if 1
	    proc1.print_trace();
	    proc1.print_stats();
	    proc1.clear_stats();
	    
	    proc2.print_trace();
	    proc2.print_stats();
	    proc2.clear_stats();
	    
	    proc3.print_trace();
	    proc3.print_stats();
	    proc3.clear_stats();
#endif
	  }

	  /*
	   * execute 10 million cycle, compute how many time it took and
	   * print the clock frequency
	   */
	  
	  if( (i % 10000000) == 0)
	  {

	    if (gettimeofday(&t2, NULL) != 0) 
	    {
	      perror("gettimeofday");
	      return EXIT_FAILURE;
	    }
	    
	    ms1 = (uint64_t)t1.tv_sec * 1000ULL + (uint64_t)t1.tv_usec / 1000;
	    ms2 = (uint64_t)t2.tv_sec * 1000ULL + (uint64_t)t2.tv_usec / 1000;
	    std::cerr << "platform clock frequency " << (double)10000000ULL / (double)(ms2 - ms1) << "Khz" << std::endl;
	   
	    if (gettimeofday(&t1, NULL) != 0) 
	    {
	      perror("gettimeofday");
	      return EXIT_FAILURE;
	    }
	  }
	}

	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;
}
