#define DEBUG_CYCLE (0)
#define DEBUG_END (DEBUG_CYCLE + 330000)
#define DEBUG
#define DEBUG_CYCLE (-1)
#define DEBUG_END (DEBUG_CYCLE + 33000)
#undef DEBUG
#include <systemc>
#include <sys/time.h>
#include <iostream>
#include <cstdlib>
#include <cstdarg>
#ifdef _OPENMP
#include <omp.h>
#endif

#include "mapping_table.h"
#include "mips32.h"
#include "vci_simple_ram.h"
#include "vci_multi_tty.h"
#include "vci_simple_ring_fast.h"
#include "vci_mem_cache_v4.h"
#include "vci_cc_vcache_wrapper_v4.h"
#include "vci_logger.h"
#include "vci_xicu.h"
#include "vci_block_device_tsar_v4.h"
#include "vci_simhelper.h"
#include "vci_framebuffer.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

#include "segmentation.h"

bool do_debug;

int _main(int argc, char *argv[])
{
	uint64_t       ms1, ms2;
	struct timeval t1, t2;
	using namespace sc_core;
	// Avoid repeating these everywhere
	using soclib::common::IntTab;
	using soclib::common::Segment;

	// set requested parallelims
#ifdef _OPENMP
	omp_set_dynamic(false);
	omp_set_num_threads(5);
	//omp_set_num_threads(1);
	std::cerr << "Built with openmp version " << _OPENMP << std::endl;
#endif

	if (argc < 3) {
		std::cerr << "usage: " << argv[0] << " <ELF boot image> <disk image>" << std::endl;
		exit(1);
	}

	// Define VCI parameters
#define    cell_width            4
#define    address_width         32
#define    plen_width            8
#define    error_width           2
#define    clen_width            1
#define    rflag_width           1
#define    srcid_width           5
#define    pktid_width           4
#define    trdid_width           4
#define    wrplen_width          1

	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;
	typedef soclib::common::Mips32ElIss proc_iss;
	// Mapping table

	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("boot", 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("simh", SIMH_BASE, SIMH_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(srcid_width), IntTab(srcid_width), 0xF0000000);
	maptabc.add(Segment("c_proc0" , 0 << (address_width - srcid_width) , 0x10 , IntTab(0), false));
	maptabc.add(Segment("c_proc1" , 1 << (address_width - srcid_width) , 0x10 , IntTab(1), false));
	maptabc.add(Segment("c_proc2" , 2 << (address_width - srcid_width) , 0x10 , IntTab(2), false));
	maptabc.add(Segment("c_proc3" , 3 << (address_width - srcid_width) , 0x10 , IntTab(3), false));
	maptabc.add(Segment("mc_m" , 4 << (address_width - srcid_width) , 0x10 , IntTab(4), false ));

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

	// Signals

	sc_clock	signal_clk ("clk");
	sc_signal<bool> *signal_resetn;
	signal_resetn = new sc_signal<bool>("resetn");

	sc_signal<bool> *signal_proc0_it0;
	sc_signal<bool> *signal_proc0_it1;
	sc_signal<bool> *signal_proc0_it2;
	sc_signal<bool> *signal_proc0_it3;
	sc_signal<bool> *signal_proc0_it4;
	sc_signal<bool> *signal_proc0_it5;

	sc_signal<bool> *signal_proc1_it0;
	sc_signal<bool> *signal_proc1_it1;
	sc_signal<bool> *signal_proc1_it2;
	sc_signal<bool> *signal_proc1_it3;
	sc_signal<bool> *signal_proc1_it4;
	sc_signal<bool> *signal_proc1_it5;

	sc_signal<bool> *signal_proc2_it0;
	sc_signal<bool> *signal_proc2_it1;
	sc_signal<bool> *signal_proc2_it2;
	sc_signal<bool> *signal_proc2_it3;
	sc_signal<bool> *signal_proc2_it4;
	sc_signal<bool> *signal_proc2_it5;

	sc_signal<bool> *signal_proc3_it0;
	sc_signal<bool> *signal_proc3_it1;
	sc_signal<bool> *signal_proc3_it2;
	sc_signal<bool> *signal_proc3_it3;
	sc_signal<bool> *signal_proc3_it4;
	sc_signal<bool> *signal_proc3_it5;

	soclib::caba::VciSignals<vci_param> *signal_vci_ini_rw_proc0;
	signal_vci_ini_rw_proc0 = new soclib::caba::VciSignals<vci_param>("vci_ini_rw_proc0");
	std::cerr << "signal_vci_ini_rw_proc0 " << sizeof(*signal_vci_ini_rw_proc0) << "@" << signal_vci_ini_rw_proc0 << std::endl;
	soclib::caba::VciSignals<vci_param> *signal_vci_ini_c_proc0;
	signal_vci_ini_c_proc0 = new soclib::caba::VciSignals<vci_param>("vci_ini_c_proc0");
	soclib::caba::VciSignals<vci_param> *signal_vci_tgt_proc0;
	signal_vci_tgt_proc0 = new soclib::caba::VciSignals<vci_param>("vci_tgt_proc0");

	soclib::caba::VciSignals<vci_param> *signal_vci_ini_rw_proc1;
	signal_vci_ini_rw_proc1 = new soclib::caba::VciSignals<vci_param>("vci_ini_rw_proc1");
	std::cerr << "signal_vci_ini_rw_proc1 " << sizeof(*signal_vci_ini_rw_proc1) << "@" << signal_vci_ini_rw_proc1 << std::endl;
	soclib::caba::VciSignals<vci_param> *signal_vci_ini_c_proc1;
	signal_vci_ini_c_proc1 = new soclib::caba::VciSignals<vci_param>("vci_ini_c_proc1");
	soclib::caba::VciSignals<vci_param> *signal_vci_tgt_proc1;
	signal_vci_tgt_proc1 = new soclib::caba::VciSignals<vci_param>("vci_tgt_proc1");

	soclib::caba::VciSignals<vci_param> *signal_vci_ini_rw_proc2;
	signal_vci_ini_rw_proc2 = new soclib::caba::VciSignals<vci_param>("vci_ini_rw_proc2");
	std::cerr << "signal_vci_ini_rw_proc2 " << sizeof(*signal_vci_ini_rw_proc2) << "@" << signal_vci_ini_rw_proc2 << std::endl;
	soclib::caba::VciSignals<vci_param> *signal_vci_ini_c_proc2;
	signal_vci_ini_c_proc2 = new soclib::caba::VciSignals<vci_param>("vci_ini_c_proc2");
	soclib::caba::VciSignals<vci_param> *signal_vci_tgt_proc2;
	signal_vci_tgt_proc2 = new soclib::caba::VciSignals<vci_param>("vci_tgt_proc2");

	soclib::caba::VciSignals<vci_param> *signal_vci_ini_rw_proc3;
	signal_vci_ini_rw_proc3 = new soclib::caba::VciSignals<vci_param>("vci_ini_rw_proc3");
	std::cerr << "signal_vci_ini_rw_proc3 " << sizeof(*signal_vci_ini_rw_proc3) << "@" << signal_vci_ini_rw_proc3 << std::endl;
	soclib::caba::VciSignals<vci_param> *signal_vci_ini_c_proc3;
	signal_vci_ini_c_proc3 = new soclib::caba::VciSignals<vci_param>("vci_ini_c_proc3");
	soclib::caba::VciSignals<vci_param> *signal_vci_tgt_proc3;
	signal_vci_tgt_proc3 = new soclib::caba::VciSignals<vci_param>("vci_tgt_proc3");

	soclib::caba::VciSignals<vci_param> *signal_vci_tty;
	signal_vci_tty = new soclib::caba::VciSignals<vci_param>("signal_vci_tty");
	soclib::caba::VciSignals<vci_param> *signal_vci_fb;
	signal_vci_fb = new soclib::caba::VciSignals<vci_param>("signal_vci_fb");
	soclib::caba::VciSignals<vci_param> *signal_vci_simh;
	signal_vci_simh = new soclib::caba::VciSignals<vci_param>("signal_vci_simh");

	
	soclib::caba::VciSignals<vci_param> *signal_vci_xicu;
	signal_vci_xicu = new soclib::caba::VciSignals<vci_param>("signal_vci_xicu");
	soclib::caba::VciSignals<vci_param> *signal_vci_vcibd_i;
	signal_vci_vcibd_i = new soclib::caba::VciSignals<vci_param>("signal_vci_vcibd_i");
	soclib::caba::VciSignals<vci_param> *signal_vci_vcibd_t;
	signal_vci_vcibd_t = new soclib::caba::VciSignals<vci_param>("signal_vci_vcibd_t");
	soclib::caba::VciSignals<vci_param> *signal_vci_tgt_rom;
	signal_vci_tgt_rom = new soclib::caba::VciSignals<vci_param>("vci_tgt_rom");

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

	sc_signal<bool> *signal_icu_irq0;
	sc_signal<bool> *signal_icu_irq1;

	soclib::common::Loader loader(argv[1]);

        //                                  init_rw   init_c   tgt
	soclib::caba::VciCcVCacheWrapperV4<vci_param, proc_iss > *proc0;
	soclib::caba::VciSimpleRam<vci_param> *rom;
	soclib::caba::VciSimpleRam<vci_param> *xram;
	soclib::caba::VciMemCacheV4<vci_param> *memc;
	soclib::caba::VciCcVCacheWrapperV4<vci_param, proc_iss > *proc1;
	soclib::caba::VciXicu<vci_param> *vcixicu;
	soclib::caba::VciMultiTty<vci_param> *vcitty;
	soclib::caba::VciFrameBuffer<vci_param> *vcifb;
	soclib::caba::VciSimhelper<vci_param> *vcisimh;
	soclib::caba::VciCcVCacheWrapperV4<vci_param, proc_iss > *proc2;
	soclib::caba::VciBlockDeviceTsarV4<vci_param> *vcibd;
	soclib::caba::VciCcVCacheWrapperV4<vci_param, proc_iss > *proc3;
	soclib::caba::VciSimpleRingFast<vci_param, 40, 33> *ringp;
	soclib::caba::VciSimpleRingFast<vci_param, 40, 33> *ringc;
#pragma omp parallel sections
  {
#pragma omp section
    {
#pragma omp critical
      {
	proc0 = new soclib::caba::VciCcVCacheWrapperV4<vci_param, proc_iss >
	  ("proc0", 0, maptabp, maptabc, IntTab(0),IntTab(0),IntTab(0),
	    8,8,8,8,4,64,16,4,64,16,4, 4, 0, 0, 4, 50000, DEBUG_CYCLE, true);
	signal_proc0_it0 = new sc_signal<bool>("mips0_it0");
	signal_proc0_it1 = new sc_signal<bool>("mips0_it1");
	signal_proc0_it2 = new sc_signal<bool>("mips0_it2");
	signal_proc0_it3 = new sc_signal<bool>("mips0_it3");
	signal_proc0_it4 = new sc_signal<bool>("mips0_it4");
	signal_proc0_it5 = new sc_signal<bool>("mips0_it5");
	vcisimh = new soclib::caba::VciSimhelper<vci_param>
	  ("vcisimh",	IntTab(5), maptabp);
	proc1 = new soclib::caba::VciCcVCacheWrapperV4<vci_param, proc_iss >
	  ("proc1", 1, maptabp, maptabc, IntTab(1),IntTab(1),IntTab(1),
	    8,8,8,8,4,64,16,4,64,16,4, 4, 0, 0, 4, 50000, DEBUG_CYCLE, true);
	signal_proc1_it0 = new sc_signal<bool>("mips1_it0");
	signal_proc1_it1 = new sc_signal<bool>("mips1_it1");
	signal_proc1_it2 = new sc_signal<bool>("mips1_it2");
	signal_proc1_it3 = new sc_signal<bool>("mips1_it3");
	signal_proc1_it4 = new sc_signal<bool>("mips1_it4");
	signal_proc1_it5 = new sc_signal<bool>("mips1_it5");
	vcitty = new soclib::caba::VciMultiTty<vci_param>
	  ("vcitty",	IntTab(3), maptabp, "vcitty0", NULL);
	vcifb = new soclib::caba::VciFrameBuffer<vci_param>
	  ("vcifb", IntTab(6), maptabp, FB_XSIZE, FB_YSIZE, soclib::common::FbController::RGB_32);

	rom = new soclib::caba::VciSimpleRam<vci_param>
	  ("rom", IntTab(1), maptabp, loader);
	vcibd = new soclib::caba::VciBlockDeviceTsarV4<vci_param>
	  ("vcitbd", maptabp, IntTab(4), IntTab(2), argv[2]);

#if 1
      }
    }
#pragma omp section
    {
#pragma omp critical
      {
#endif
	proc2 = new soclib::caba::VciCcVCacheWrapperV4<vci_param, proc_iss >
	  ("proc2", 2, maptabp, maptabc, IntTab(2),IntTab(2),IntTab(2),
	    8,8,8,8,4,64,16,4,64,16,4, 4, 0, 0, 4, 50000, DEBUG_CYCLE, true);
	signal_proc2_it0 = new sc_signal<bool>("mips2_it0");
	signal_proc2_it1 = new sc_signal<bool>("mips2_it1");
	signal_proc2_it2 = new sc_signal<bool>("mips2_it2");
	signal_proc2_it3 = new sc_signal<bool>("mips2_it3");
	signal_proc2_it4 = new sc_signal<bool>("mips2_it4");
	signal_proc2_it5 = new sc_signal<bool>("mips2_it5");
	vcixicu = new soclib::caba::VciXicu<vci_param>
	  ("vcixicu", maptabp, IntTab(4), 4 /* npti */, 2 /* nhwi */, 4 /* nwti */, 12 /* nirq */);
	signal_icu_irq0 = new sc_signal<bool>("signal_xicu_irq0");
	signal_icu_irq1 = new sc_signal<bool>("signal_xicu_irq1");
#if 1
      }
    }
#pragma omp section
    {
#pragma omp critical
      {
#endif
	ringc = new soclib::caba::VciSimpleRingFast<vci_param, 40, 33>
	  ("ringc",maptabc, IntTab(), 4, 5, 5);
#if 1
      }
    }
#pragma omp section
    {
#pragma omp critical
      {
#endif
	ringp = new soclib::caba::VciSimpleRingFast<vci_param, 40, 33> 
	  ("ringp",maptabp, IntTab(), 4, 5, 7);
#if 1
      }
    }
#pragma omp section
    {
#pragma omp critical
      {
#endif
	proc3 = new soclib::caba::VciCcVCacheWrapperV4<vci_param, proc_iss >
	  ("proc3", 3, maptabp, maptabc, IntTab(3),IntTab(3),IntTab(3),
	    8,8,8,8,4,64,16,4,64,16,4, 4, 0, 0, 4, 50000, DEBUG_CYCLE, true);
	signal_proc3_it0 = new sc_signal<bool>("mips3_it0");
	signal_proc3_it1 = new sc_signal<bool>("mips3_it1");
	signal_proc3_it2 = new sc_signal<bool>("mips3_it2");
	signal_proc3_it3 = new sc_signal<bool>("mips3_it3");
	signal_proc3_it4 = new sc_signal<bool>("mips3_it4");
	signal_proc3_it5 = new sc_signal<bool>("mips3_it5");
	xram = new soclib::caba::VciSimpleRam<vci_param>
	  ("xram", IntTab(0), maptabx, loader);
	memc = new soclib::caba::VciMemCacheV4<vci_param>
	  ("memc",maptabp,maptabc,maptabx,IntTab(0),IntTab(4),IntTab(0), IntTab(4),16,256,16, 1024, 4, 4, DEBUG_CYCLE, true);
	signal_vci_ixr_memc = new soclib::caba::VciSignals<vci_param>("vci_ixr_memc");
#ifdef VCI_LOGGER_ON_L1
	soclib::caba::VciLogger<vci_param> vci_logger0("vci_logger0",maptabp);
#endif
#ifdef VCI_LOGGER_ON_ROM
	soclib::caba::VciLogger<vci_param> vci_logger1("vci_logger1",maptabp);
#endif
#ifdef VCI_LOGGER_ON_L1_TGT
	soclib::caba::VciLogger<vci_param> vci_logger2("vci_logger2",maptabp);
#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_d(*signal_vci_ini_rw_proc0);
	proc0->p_vci_ini_c(*signal_vci_ini_c_proc0);
	proc0->p_vci_tgt_c(*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_d(*signal_vci_ini_rw_proc1);
	proc1->p_vci_ini_c(*signal_vci_ini_c_proc1);
	proc1->p_vci_tgt_c(*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_d(*signal_vci_ini_rw_proc2);
	proc2->p_vci_ini_c(*signal_vci_ini_c_proc2);
	proc2->p_vci_tgt_c(*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_d(*signal_vci_ini_rw_proc3);
	proc3->p_vci_ini_c(*signal_vci_ini_c_proc3);
	proc3->p_vci_tgt_c(*signal_vci_tgt_proc3);

	rom->p_clk(signal_clk);
	rom->p_resetn(*signal_resetn);
	rom->p_vci(*signal_vci_tgt_rom);

	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_irq[0](*signal_proc0_it0);
	vcixicu->p_irq[1](*signal_proc0_it1);
	vcixicu->p_irq[2](*signal_proc0_it2);
	vcixicu->p_irq[3](*signal_proc1_it0);
	vcixicu->p_irq[4](*signal_proc1_it1);
	vcixicu->p_irq[5](*signal_proc1_it2);
	vcixicu->p_irq[6](*signal_proc2_it0);
	vcixicu->p_irq[7](*signal_proc2_it1);
	vcixicu->p_irq[8](*signal_proc2_it2);
	vcixicu->p_irq[9](*signal_proc3_it0);
	vcixicu->p_irq[10](*signal_proc3_it1);
	vcixicu->p_irq[11](*signal_proc3_it2);

#ifdef VCI_LOGGER_ON_L1
  vci_logger0.p_clk(signal_clk);
  vci_logger0.p_resetn(*signal_resetn);
  vci_logger0.p_vci(*signal_vci_ini_rw_proc0);
#endif

#ifdef VCI_LOGGER_ON_ROM
  vci_logger1.p_clk(signal_clk);
  vci_logger1.p_resetn(*signal_resetn);
  vci_logger1.p_vci(*signal_vci_tgt_rom);
#endif

#ifdef VCI_LOGGER_ON_L1_TGT
  vci_logger2.p_clk(signal_clk);
  vci_logger2.p_resetn(*signal_resetn);
  vci_logger2.p_vci(*signal_vci_tgt_proc1);
#endif

	vcitty->p_clk(signal_clk);
	vcitty->p_resetn(*signal_resetn);
	vcitty->p_vci(*signal_vci_tty);
	vcitty->p_irq[0](*signal_icu_irq0);

	vcisimh->p_clk(signal_clk);
	vcisimh->p_resetn(*signal_resetn);
	vcisimh->p_vci(*signal_vci_simh);

	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_irq1);

	vcifb->p_clk(signal_clk);
	vcifb->p_resetn(*signal_resetn);
	vcifb->p_vci(*signal_vci_fb);

	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_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_simh);
	ringp->p_to_target[6](*signal_vci_fb);
	
	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;
	/*
	 * execute 10 million cycle, compute how many time it took and
	 * print the clock frequency
	 */
#ifndef DEBUG
//#define  	STATS_CYCLES 100000000ULL
#define  	STATS_CYCLES 1000000ULL
	int n = 0;
	do_debug = 0;
no_debug:
	proc0->iss_set_debug_mask(0);
	proc1->iss_set_debug_mask(0);
	proc2->iss_set_debug_mask(0);
	proc3->iss_set_debug_mask(0);
	while (do_debug == 0) {
		if (gettimeofday(&t1, NULL) != 0) {
			perror("gettimeofday");
			return EXIT_FAILURE;
		}
		sc_start(STATS_CYCLES);
		n += STATS_CYCLES;
		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 << "cycle " << n << " platform clock frequency " << (double)STATS_CYCLES / (double)(ms2 - ms1) << "Khz" << std::endl;
	}
	proc0->iss_set_debug_mask(MIPS32_DEBUG_CPU|MIPS32_DEBUG_DATA);
	proc1->iss_set_debug_mask(MIPS32_DEBUG_CPU|MIPS32_DEBUG_DATA);
	proc2->iss_set_debug_mask(MIPS32_DEBUG_CPU|MIPS32_DEBUG_DATA);
	proc3->iss_set_debug_mask(MIPS32_DEBUG_CPU|MIPS32_DEBUG_DATA);
	while (do_debug) {
		proc0->print_trace();
	        signal_vci_ini_rw_proc0->print_trace("proc_ini_d");
		signal_vci_tgt_proc0->print_trace("proc_tgt_c");
	        signal_vci_ini_c_proc0->print_trace("proc_ini_c");

		proc1->print_trace();
	        signal_vci_ini_rw_proc1->print_trace("proc_ini_d");
		signal_vci_tgt_proc1->print_trace("proc_tgt_c");
	        signal_vci_ini_c_proc1->print_trace("proc_ini_c");

		proc2->print_trace();
	        signal_vci_ini_rw_proc2->print_trace("proc_ini_d");
		signal_vci_tgt_proc2->print_trace("proc_tgt_c");
	        signal_vci_ini_c_proc2->print_trace("proc_ini_c");

		proc3->print_trace();
	        signal_vci_ini_rw_proc3->print_trace("proc_ini_d");
		signal_vci_tgt_proc3->print_trace("proc_tgt_c");
	        signal_vci_ini_c_proc3->print_trace("proc_ini_c");

		memc->print_trace();
		signal_vci_tgt_memc->print_trace("memc_tgt_d");
		signal_vci_tgt_cleanup_memc->print_trace("memc_tgt_c");
		signal_vci_ini_memc->print_trace("memc_ini_c");
		n++;
		sc_start(sc_core::sc_time(1, SC_NS));
	}
	goto no_debug;
	//sc_start(250000000);
#else
	memc->start_monitor(0x12fc, 4);
	proc0->iss_set_debug_mask(0);
	proc1->iss_set_debug_mask(0);
	proc2->iss_set_debug_mask(0);
	proc3->iss_set_debug_mask(0);
	sc_start(DEBUG_CYCLE);
	int n = DEBUG_CYCLE;
	proc0->iss_set_debug_mask(MIPS32_DEBUG_CPU|MIPS32_DEBUG_DATA);
	proc1->iss_set_debug_mask(MIPS32_DEBUG_CPU|MIPS32_DEBUG_DATA);
	proc2->iss_set_debug_mask(MIPS32_DEBUG_CPU|MIPS32_DEBUG_DATA);
	proc3->iss_set_debug_mask(MIPS32_DEBUG_CPU|MIPS32_DEBUG_DATA);
#if 0
	while (n < DEBUG_END) {
		std::cout << "cycle " << std::dec << n << std::endl;
		sc_start(10000);
		n+= 10000;
	}
#endif
	while (n < DEBUG_END) {
		std::cout << "****************** cycle " << std::dec << n
		    		<< std::endl;
		proc0->cache_monitor(0x12fc);
		proc0->print_trace();
	        signal_vci_ini_rw_proc0->print_trace("proc_ini_d");
		signal_vci_tgt_proc0->print_trace("proc_tgt_c");
	        signal_vci_ini_c_proc0->print_trace("proc_ini_c");

		proc1->print_trace();
	        signal_vci_ini_rw_proc1->print_trace("proc_ini_d");
		signal_vci_tgt_proc1->print_trace("proc_tgt_c");
	        signal_vci_ini_c_proc1->print_trace("proc_ini_c");

		proc2->print_trace();
	        signal_vci_ini_rw_proc2->print_trace("proc_ini_d");
		signal_vci_tgt_proc2->print_trace("proc_tgt_c");
	        signal_vci_ini_c_proc2->print_trace("proc_ini_c");

		proc3->print_trace();
	        signal_vci_ini_rw_proc3->print_trace("proc_ini_d");
		signal_vci_tgt_proc3->print_trace("proc_tgt_c");
	        signal_vci_ini_c_proc3->print_trace("proc_ini_c");

		memc->print_trace();
		signal_vci_tgt_memc->print_trace("memc_tgt_d");
		signal_vci_tgt_cleanup_memc->print_trace("memc_tgt_c");
		signal_vci_ini_memc->print_trace("memc_ini_c");
		n++;
		sc_start(sc_core::sc_time(1, SC_NS));
	}
#endif

	return EXIT_FAILURE;

}

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

