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

#include "mapping_table.h"
#include "mips32.h"
#include "vci_simple_ram.h"
#include "vci_multi_tty.h"
#include "vci_local_ring_network_2.h"
#include "vci_mem_cache_v4.h"
#include "vci_cc_xcache_wrapper_v4.h"
#include "vci_logger.h"
#include "vci_timer.h"
#include "vci_icu.h"
#include "vci_dma_tsar_v2.h"
#include "vci_framebuffer.h"
#include "vci_block_device_tsar_v2.h"
#include "vci_vgmn.h"
#include "virtual_dspin_network.h"

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

#include "segmentation.h"

//#define  VCI_LOGGER_ON_L1

#define CYCLES 100000
int _main(int argc, char *argv[])
{
	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 primary network

	soclib::common::MappingTable maptabp(32, IntTab(2,10), IntTab(4,4), 0xFFC00000);

  // CLUSTER 0 : 0x00000000 -> 0x3FFFFFFF
	maptabp.add(Segment("mc_m0" , MC0_M_BASE , MC0_M_SIZE , IntTab(0,0), true ));
	maptabp.add(Segment("timer0", TIMER0_BASE, TIMER0_SIZE, IntTab(0,1), false));

  // CLUSTER 1 : 0x40000000 -> 0x7FFFFFFF
	maptabp.add(Segment("mc_m1" , MC1_M_BASE , MC1_M_SIZE , IntTab(1,0), true ));
	maptabp.add(Segment("timer1", TIMER1_BASE, TIMER1_SIZE, IntTab(1,1), false));

  // CLUSTER 2 : 0x80000000 -> 0xBFFFFFFF
	maptabp.add(Segment("mc_m2" , MC2_M_BASE , MC2_M_SIZE , IntTab(2,0), true ));
	maptabp.add(Segment("timer2", TIMER2_BASE, TIMER2_SIZE, IntTab(2,1), false));

	maptabp.add(Segment("boot", BOOT_BASE, BOOT_SIZE, IntTab(2,2), true));
	maptabp.add(Segment("ktext" , KTEXT_LMA_BASE , KTEXT_LMA_SIZE , IntTab(2,2), true));
	maptabp.add(Segment("kdata" , KDATA_LMA_BASE , KDATA_LMA_SIZE , IntTab(2,2), true));
	
	maptabp.add(Segment("data" , UDATA_LMA_BASE , UDATA_LMA_SIZE , IntTab(2,2), true));
	maptabp.add(Segment("text" , UTEXT_LMA_BASE , UTEXT_LMA_SIZE , IntTab(2,2), true));

	maptabp.add(Segment("tty"  , TTY_BASE  , TTY_SIZE  , IntTab(2,3), false));
	maptabp.add(Segment("icu", ICU_BASE, ICU_SIZE, IntTab(2,4), false));
	maptabp.add(Segment("dma", DMA_BASE, DMA_SIZE, IntTab(2,5), false));
	maptabp.add(Segment("bd", BD_BASE, BD_SIZE, IntTab(2,6), false));

  // CLUSTER 3 : 0xC0000000 -> 0xFFFFFFFFF
	maptabp.add(Segment("mc_m3" , MC3_M_BASE , MC3_M_SIZE , IntTab(3,0), true ));
	maptabp.add(Segment("timer3", TIMER3_BASE, TIMER3_SIZE, IntTab(3,1), false));
	maptabp.add(Segment("fb", FB_BASE, FB_SIZE, IntTab(3,2), false));

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

	// Mapping table coherence network

	soclib::common::MappingTable maptabc(32, IntTab(2,10), IntTab(4,4), 0x00C00000);

	maptabc.add(Segment("proc0" , PROC0_BASE , PROC0_SIZE , IntTab(0,0), false, true, IntTab(0,0)));
	maptabc.add(Segment("proc1" , PROC1_BASE , PROC1_SIZE , IntTab(0,1), false, true, IntTab(0,1)));
	maptabc.add(Segment("proc2" , PROC2_BASE , PROC2_SIZE , IntTab(0,2), false, true, IntTab(0,2)));
	maptabc.add(Segment("proc3" , PROC3_BASE , PROC3_SIZE , IntTab(0,3), false, true, IntTab(0,3)));
	maptabc.add(Segment("proc4" , PROC4_BASE , PROC4_SIZE , IntTab(1,0), false, true, IntTab(1,0)));
	maptabc.add(Segment("proc5" , PROC5_BASE , PROC5_SIZE , IntTab(1,1), false, true, IntTab(1,1)));
	maptabc.add(Segment("proc6" , PROC6_BASE , PROC6_SIZE , IntTab(1,2), false, true, IntTab(1,2)));
	maptabc.add(Segment("proc7" , PROC7_BASE , PROC7_SIZE , IntTab(1,3), false, true, IntTab(1,3)));
	maptabc.add(Segment("proc8" , PROC8_BASE , PROC8_SIZE , IntTab(2,0), false, true, IntTab(2,0)));
	maptabc.add(Segment("proc9" , PROC9_BASE , PROC9_SIZE , IntTab(2,1), false, true, IntTab(2,1)));
	maptabc.add(Segment("proc10" , PROC10_BASE , PROC10_SIZE , IntTab(2,2), false, true, IntTab(2,2)));
	maptabc.add(Segment("proc11" , PROC11_BASE , PROC11_SIZE , IntTab(2,3), false, true, IntTab(2,3)));
	maptabc.add(Segment("proc12" , PROC12_BASE , PROC12_SIZE , IntTab(3,0), false, true, IntTab(3,0)));
	maptabc.add(Segment("proc13" , PROC13_BASE , PROC13_SIZE , IntTab(3,1), false, true, IntTab(3,1)));
	maptabc.add(Segment("proc14" , PROC14_BASE , PROC14_SIZE , IntTab(3,2), false, true, IntTab(3,2)));
	maptabc.add(Segment("proc15" , PROC15_BASE , PROC15_SIZE , IntTab(3,3), false, true, IntTab(3,3)));

	maptabc.add(Segment("mc_m0" , MC0_M_BASE , MC0_M_SIZE , IntTab(0,4), false ));
	maptabc.add(Segment("mc_m1" , MC1_M_BASE , MC1_M_SIZE , IntTab(1,4), false ));
	maptabc.add(Segment("mc_m2" , MC2_M_BASE , MC2_M_SIZE , IntTab(2,4), false ));
	maptabc.add(Segment("mc_m3" , MC3_M_BASE , MC3_M_SIZE , IntTab(3,4), false ));

	maptabc.add(Segment("boot", BOOT_BASE, BOOT_SIZE, IntTab(2,4), false));
	maptabc.add(Segment("ktext" , KTEXT_LMA_BASE , KTEXT_LMA_SIZE , IntTab(2,4), false));
	maptabc.add(Segment("kdata" , KDATA_LMA_BASE , KDATA_LMA_SIZE , IntTab(2,4), false));
	
	maptabc.add(Segment("data" , UDATA_LMA_BASE , UDATA_LMA_SIZE , IntTab(2,4), false));
	maptabc.add(Segment("text" , UTEXT_LMA_BASE , UTEXT_LMA_SIZE , IntTab(2,4), false));


	std::cout << maptabc << std::endl;

	// Mapping table external network

	soclib::common::MappingTable maptabx(32, IntTab(8,4), IntTab(4,4), 0x00C00000);
	maptabx.add(Segment("xram0" , MC0_M_BASE , MC0_M_SIZE , IntTab(0,0), false));
	maptabx.add(Segment("xram1" , MC1_M_BASE , MC1_M_SIZE , IntTab(0,0), false));
	maptabx.add(Segment("xram2" , MC2_M_BASE , MC2_M_SIZE , IntTab(0,0), false));
	maptabx.add(Segment("xram3" , MC3_M_BASE , MC3_M_SIZE , IntTab(0,0), false));
	std::cout << maptabx << std::endl;

	// Signals

	sc_clock	signal_clk("clk");
	sc_signal<bool> signal_resetn("resetn");
   
	sc_signal<bool> ** signal_proc_it = soclib::common::alloc_elems<sc_signal<bool> >("signal_proc_it", 16, 6);

	soclib::caba::VciSignals<vci_param> * signal_vci_ini_rw_proc = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_ini_rw_proc", 16);
	soclib::caba::VciSignals<vci_param> * signal_vci_ini_c_proc = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_ini_c_proc", 16);
	soclib::caba::VciSignals<vci_param> * signal_vci_tgt_proc = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_tgt_proc", 16);

	soclib::caba::VciSignals<vci_param> signal_vci_tgt_tty("vci_tgt_tty");

	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 = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_ixr_memc", 4);
	soclib::caba::VciSignals<vci_param> * signal_vci_ini_memc = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_ini_memc", 4);
	soclib::caba::VciSignals<vci_param> * signal_vci_tgt_memc = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_tgt_memc", 4);
	soclib::caba::VciSignals<vci_param> * signal_vci_tgt_cleanup_memc = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_tgt_cleanup_memc", 4);

	soclib::caba::VciSignals<vci_param> signal_vci_icu("signal_vci_icu");
	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_t("signal_vci_vcibd_t");
	soclib::caba::VciSignals<vci_param> signal_vci_vcibd_i("signal_vci_vcibd_i");

	soclib::caba::VciSignals<vci_param> * signal_vci_vcitimer = soclib::common::alloc_elems<soclib::caba::VciSignals<vci_param> >("signal_vci_vcitimer",4);

	sc_signal<bool> signal_icu_irq0("signal_icu_irq0");
	sc_signal<bool> signal_icu_irq1("signal_icu_irq1");
	sc_signal<bool> signal_icu_irq2("signal_icu_irq2");
	sc_signal<bool> signal_icu_irq3("signal_icu_irq3");
	sc_signal<bool> signal_icu_irq4("signal_icu_irq4");
	sc_signal<bool> signal_icu_irq5("signal_icu_irq5");
	sc_signal<bool> signal_icu_irq6("signal_icu_irq6");

	sc_signal<bool> signal_tty_irq4("signal_tty_irq4"); 
	sc_signal<bool> signal_tty_irq5("signal_tty_irq5"); 
	sc_signal<bool> signal_tty_irq6("signal_tty_irq6"); 
	sc_signal<bool> signal_tty_irq7("signal_tty_irq7"); 
	sc_signal<bool> signal_tty_irq8("signal_tty_irq8"); 
	sc_signal<bool> signal_tty_irq9("signal_tty_irq9"); 
	sc_signal<bool> signal_tty_irq10("signal_tty_irq10"); 
	sc_signal<bool> signal_tty_irq11("signal_tty_irq11"); 
	sc_signal<bool> signal_tty_irq12("signal_tty_irq12"); 
	sc_signal<bool> signal_tty_irq13("signal_tty_irq13"); 
	sc_signal<bool> signal_tty_irq14("signal_tty_irq14"); 
	sc_signal<bool> signal_tty_irq15("signal_tty_irq15"); 


	soclib::caba::GateSignals2<37,33> gate_PN[4][2];
	soclib::caba::GateSignals2<37,33> gate_CN[4][2];



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

	// VCI ports indexation : 3 initiateurs et 5 cibles

        // INIT0 : proc0_ini
        // INIT1 : memc_ini
        // INIT2 : memc_ixr

	// TGT 0 : rom_tgt
	// TGT 1 : tty_tgt
        // TGT 2 : xram_tgt
	// TGT 3 : memc_tgt
	// TGT 4 : proc0_tgt

	soclib::common::Loader loader("soft/bin.soft");

	// 16 MIPS processors (4 processors per cluster)
	soclib::caba::VciCcXCacheWrapperV4<vci_param, proc_iss> * proc = (soclib::caba::VciCcXCacheWrapperV4<vci_param, proc_iss > *) malloc(sizeof(soclib::caba::VciCcXCacheWrapperV4<vci_param, proc_iss> )*16);
	for(int i=0; i<4; i++)
		for(int j=0; j<4; j++)
                  new(&proc[4*i+j]) soclib::caba::VciCcXCacheWrapperV4<vci_param, proc_iss> ("proc" + (4*i+j), 4*i+j, maptabp, maptabc,IntTab(i,j),IntTab(i,j),IntTab(i,j),4,64,16,4,64,16,4,8,16);

	// ROM which contains boot code
	soclib::caba::VciSimpleRam<vci_param> 
	rom("rom", IntTab(2,2), maptabp, loader);

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

	// Distributed memory caches (1 memory cache per cluster)
	soclib::caba::VciMemCacheV4<vci_param> * memc = (soclib::caba::VciMemCacheV4<vci_param> *) malloc(sizeof(soclib::caba::VciMemCacheV4<vci_param>)*4);
	for(int i=0; i<4; i++) //  x_init    c_init    p_tgt     c_tgt
		new(&memc[i]) soclib::caba::VciMemCacheV4<vci_param>("memc" + (i),maptabp,maptabc,maptabx,IntTab(i,0),IntTab(i,4),IntTab(i,0),IntTab(i,4),16,256,16,4096);

	// Multi TTY Controller : 1 display per processor	
	soclib::caba::VciMultiTty<vci_param> 
	tty("tty",IntTab(2,3),maptabp,"tty0","tty1","tty2","tty3","tty4","tty5","tty6","tty7","tty8","tty9","tty10","tty11","tty12","tty13","tty14","tty15",NULL);

  // ICU controller : 1 in the third cluster
	soclib::caba::VciIcu<vci_param> vciicu("vciicu", IntTab(2,4), maptabp,7);

  // Dma controller : 1 in the third custer
	soclib::caba::VciDmaTsarV2<vci_param> vcidma("vcidma", maptabp, IntTab(2,4), IntTab(2,5), 64);//(1<<(vci_param::K-1))); 

  // Block device : 1 in the third cluster
	soclib::caba::VciBlockDeviceTsarV2<vci_param> vcibd("vcitbd", maptabp, IntTab(2,5), IntTab(2,6), "hdd-img.bin");

  // FrameBuffer : 1 in the fourth cluster
	soclib::caba::VciFrameBuffer<vci_param> vcifb("vcifb", IntTab(3,2), maptabp, FB_XSIZE, FB_YSIZE);

  // Multi Timer, 1 per cluster
	soclib::caba::VciTimer<vci_param> * vcitimer = (soclib::caba::VciTimer<vci_param> *) malloc(sizeof(soclib::caba::VciTimer<vci_param>)*4);
  for(int i=0; i<4; i++)
    new(&vcitimer[i]) soclib::caba::VciTimer<vci_param>("vcittimer"+i, IntTab(i,1), maptabp, 4);

	// Local ring interconnects : 1 direct ring per cluster
	soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> * clusterPN = (soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> *) malloc(sizeof(soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> )*4);
	
	new(&clusterPN[0]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterPN0",maptabp, IntTab(0), 2, 18, 4, 2 );
	new(&clusterPN[1]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterPN1",maptabp, IntTab(1), 2, 18, 4, 2 );
	new(&clusterPN[2]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterPN2",maptabp, IntTab(2), 2, 18, 6, 7 );
	new(&clusterPN[3]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterPN3",maptabp, IntTab(3), 2, 18, 4, 3 );

        // Local ring interconnects : 1 coherence ring per cluster
	soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> * clusterCN = (soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> *) malloc(sizeof(soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> )*4);

	new(&clusterCN[0]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterCN0",maptabc, IntTab(0), 2, 18, 5, 5 );
	new(&clusterCN[1]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterCN1",maptabc, IntTab(1), 2, 18, 5, 5 );
	new(&clusterCN[2]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterCN2",maptabc, IntTab(2), 2, 18, 5, 5 );
	new(&clusterCN[3]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterCN3",maptabc, IntTab(3), 2, 18, 5, 5 );

	// Local ring interconnects : 1 coherence ring per cluster
	//soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> * clusterCN = (soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> *) malloc(sizeof(soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33> )*4);
	//for(int i=0; i<4; i++)
	//	new(&clusterCN[i]) soclib::caba::VciLocalRingNetwork2<vci_param, 37, 33>("clusterCN" + i,maptabc, IntTab(i), 2, 2, 5, 5 );

	// External network
	soclib::caba::VciVgmn<vci_param> 
	xring("xring",maptabx, 4, 1, 2, 8);

	// Global interconnect : virtual dspin
	soclib::caba::VirtualDspinNetwork<2, 2, 1, 1, 37, 1, 3, 6, 7, 0, 36, 33, 1, 3, 15, 16, 0, 18, 18, 32, 33, 34, 35> network("network", 2, 2, NULL);

	///////////////////////////////////////////////////////////////
	// Net-list description
	///////////////////////////////////////////////////////////////

	// Virtual Dspin Network
	network.p_clk(signal_clk);
	network.p_resetn(signal_resetn);
	for(int i=0; i<2; i++){
		for(int j=0; j<2; j++){
			// GatePN[][1]
			network.p_out_cmd[0][i][j].data(	gate_PN[j+2*i][1].cmd_data);
			network.p_out_cmd[0][i][j].read(	gate_PN[j+2*i][1].cmd_r_wok);
			network.p_out_cmd[0][i][j].write(	gate_PN[j+2*i][1].cmd_w_rok);
			network.p_in_rsp[0][i][j].data(		gate_PN[j+2*i][1].rsp_data);
			network.p_in_rsp[0][i][j].read(		gate_PN[j+2*i][1].rsp_r_wok);
			network.p_in_rsp[0][i][j].write(	gate_PN[j+2*i][1].rsp_w_rok);
			// GateCN[][1]
			network.p_out_cmd[1][i][j].data(	gate_CN[j+2*i][1].cmd_data);
			network.p_out_cmd[1][i][j].read(	gate_CN[j+2*i][1].cmd_r_wok);
			network.p_out_cmd[1][i][j].write(	gate_CN[j+2*i][1].cmd_w_rok);
			network.p_in_rsp[1][i][j].data(		gate_CN[j+2*i][1].rsp_data);
			network.p_in_rsp[1][i][j].read(		gate_CN[j+2*i][1].rsp_r_wok);
			network.p_in_rsp[1][i][j].write(	gate_CN[j+2*i][1].rsp_w_rok);
			// GatePN[][0]
			network.p_in_cmd[0][i][j].data(		gate_PN[j+2*i][0].cmd_data);
			network.p_in_cmd[0][i][j].read(		gate_PN[j+2*i][0].cmd_r_wok);
			network.p_in_cmd[0][i][j].write(	gate_PN[j+2*i][0].cmd_w_rok);
			network.p_out_rsp[0][i][j].data(	gate_PN[j+2*i][0].rsp_data);
			network.p_out_rsp[0][i][j].read(	gate_PN[j+2*i][0].rsp_r_wok);
			network.p_out_rsp[0][i][j].write(	gate_PN[j+2*i][0].rsp_w_rok);
			// GateCN[][0]
			network.p_in_cmd[1][i][j].data(		gate_CN[j+2*i][0].cmd_data);
			network.p_in_cmd[1][i][j].read(		gate_CN[j+2*i][0].cmd_r_wok);
			network.p_in_cmd[1][i][j].write(	gate_CN[j+2*i][0].cmd_w_rok);
			network.p_out_rsp[1][i][j].data(	gate_CN[j+2*i][0].rsp_data);
			network.p_out_rsp[1][i][j].read(	gate_CN[j+2*i][0].rsp_r_wok);
			network.p_out_rsp[1][i][j].write(	gate_CN[j+2*i][0].rsp_w_rok);
		}
	}
        
	// Processors
	for(int i=0; i<16; i++){
		proc[i].p_clk(signal_clk);  
		proc[i].p_resetn(signal_resetn);  
		proc[i].p_vci_ini_rw(signal_vci_ini_rw_proc[i]);
		proc[i].p_vci_ini_c(signal_vci_ini_c_proc[i]);
		proc[i].p_vci_tgt(signal_vci_tgt_proc[i]);
		for(int j=0; j<6; j++)
			proc[i].p_irq[j](signal_proc_it[i][j]); 
	}
#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_proc[0]);
#endif

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

	// TTY
	tty.p_clk(signal_clk);
	tty.p_resetn(signal_resetn);
	tty.p_vci(signal_vci_tgt_tty);
	tty.p_irq[0](signal_icu_irq1); 
	tty.p_irq[1](signal_icu_irq2); 
	tty.p_irq[2](signal_icu_irq3); 
	tty.p_irq[3](signal_icu_irq4); 
	tty.p_irq[4](signal_tty_irq4);
	tty.p_irq[5](signal_tty_irq5);
	tty.p_irq[6](signal_tty_irq6);
	tty.p_irq[7](signal_tty_irq7); 
	tty.p_irq[8](signal_tty_irq8);
	tty.p_irq[9](signal_tty_irq9);
	tty.p_irq[10](signal_tty_irq10);
	tty.p_irq[11](signal_tty_irq11); 
	tty.p_irq[12](signal_tty_irq12);
	tty.p_irq[13](signal_tty_irq13);
	tty.p_irq[14](signal_tty_irq14);
	tty.p_irq[15](signal_tty_irq15);  

  // DMA
	vcidma.p_clk(signal_clk);
	vcidma.p_resetn(signal_resetn);
	vcidma.p_vci_target(signal_vci_dmat);
	vcidma.p_vci_initiator(signal_vci_dmai);
	vcidma.p_irq(signal_icu_irq5); 

  // Block Device
	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_irq6);

  // Frame Buffer
	vcifb.p_clk(signal_clk);
	vcifb.p_resetn(signal_resetn);
	vcifb.p_vci(signal_vci_vcifb);

  // TIMERs
  for(int i=0; i<4; i++){
    vcitimer[i].p_clk(signal_clk);
    vcitimer[i].p_resetn(signal_resetn);
    vcitimer[i].p_vci(signal_vci_vcitimer[i]);
    vcitimer[i].p_irq[1](signal_proc_it[1+i*4][0]); 
    vcitimer[i].p_irq[2](signal_proc_it[2+i*4][0]); 
    vcitimer[i].p_irq[3](signal_proc_it[3+i*4][0]);
  }
  for(int i=0; i<4; i++){
    if(i!=2){
      vcitimer[i].p_irq[0](signal_proc_it[0+i*4][0]); 
    }
  }
  vcitimer[2].p_irq[0](signal_icu_irq0);

  // ICU
	vciicu.p_clk(signal_clk);
	vciicu.p_resetn(signal_resetn);
	vciicu.p_vci(signal_vci_icu);
	vciicu.p_irq_in[0](signal_icu_irq0);
	vciicu.p_irq_in[1](signal_icu_irq1);
	vciicu.p_irq_in[2](signal_icu_irq2);
	vciicu.p_irq_in[3](signal_icu_irq3);
	vciicu.p_irq_in[4](signal_icu_irq4);
	vciicu.p_irq_in[5](signal_icu_irq5);
	vciicu.p_irq_in[6](signal_icu_irq6);
	vciicu.p_irq(signal_proc_it[8][0]);


	// Memory caches
	for(int i=0; i<4; i++){
		memc[i].p_clk(signal_clk);
		memc[i].p_resetn(signal_resetn);
		memc[i].p_vci_tgt(signal_vci_tgt_memc[i]);	
		memc[i].p_vci_ini(signal_vci_ini_memc[i]);
		memc[i].p_vci_tgt_cleanup(signal_vci_tgt_cleanup_memc[i]);
		memc[i].p_vci_ixr(signal_vci_ixr_memc[i]);
	}

	// XRAM
	xram.p_clk(signal_clk);
        xram.p_resetn(signal_resetn);
	xram.p_vci(signal_vci_tgt_xram);	

	// XRING
	xring.p_clk(signal_clk);
	xring.p_resetn(signal_resetn);
	for(int i=0; i<4; i++)
		xring.p_to_initiator[i](signal_vci_ixr_memc[i]);
	xring.p_to_target[0](signal_vci_tgt_xram);

	// direct ring
	for(int i=0; i<4; i++){
		clusterPN[i].p_clk(signal_clk);
		clusterPN[i].p_resetn(signal_resetn);
		clusterPN[i].p_to_target[0](signal_vci_tgt_memc[i]);
		clusterPN[i].p_to_target[1](signal_vci_vcitimer[i]);
                clusterPN[i].p_gate_initiator(gate_PN[i][1]);
		clusterPN[i].p_gate_target(gate_PN[i][0]);
		for(int j=0; j<4; j++)
			clusterPN[i].p_to_initiator[j](signal_vci_ini_rw_proc[i*4+j]);
	}

	clusterPN[2].p_to_initiator[4](signal_vci_dmai);
	clusterPN[2].p_to_initiator[5](signal_vci_vcibd_i);

	clusterPN[2].p_to_target[2](signal_vci_tgt_rom);
	clusterPN[2].p_to_target[3](signal_vci_tgt_tty);
	clusterPN[2].p_to_target[4](signal_vci_icu);
	clusterPN[2].p_to_target[5](signal_vci_dmat);
	clusterPN[2].p_to_target[6](signal_vci_vcibd_t);
	clusterPN[3].p_to_target[2](signal_vci_vcifb);

	// coherence ring
	for(int i=0; i<4; i++){
		clusterCN[i].p_clk(signal_clk);
		clusterCN[i].p_resetn(signal_resetn);
		clusterCN[i].p_to_initiator[4](signal_vci_ini_memc[i]);
		clusterCN[i].p_to_target[4](signal_vci_tgt_cleanup_memc[i]);
		clusterCN[i].p_gate_initiator(gate_CN[i][1]);
		clusterCN[i].p_gate_target(gate_CN[i][0]);
		for(int j=0; j<4; j++){
			clusterCN[i].p_to_target[j](signal_vci_tgt_proc[i*4+j]);
			clusterCN[i].p_to_initiator[j](signal_vci_ini_c_proc[i*4+j]);
    }
	}

	////////////////////////////////////////////////////////

	int ncycles;
#ifndef SOCVIEW

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

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

	while(1)
	{
	  sc_start(sc_core::sc_time(CYCLES, SC_NS));

  	}

        std::cout << "Hit ENTER to end simulation" << std::endl;
        char buf[1];

	std::cin.getline(buf,1);

	return EXIT_SUCCESS;
#else
	ncycles = 1;
	sc_start(sc_core::sc_time(0, SC_NS));
	signal_resetn = false;
	sc_start(sc_core::sc_time(1, SC_NS));
	signal_resetn = true;

	debug();
	return EXIT_SUCCESS;
#endif
}

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