#include "hierarchy_memory.h"
#include <systemc.h>
#include <iostream>

#define	TEXT_BASE		0x00000000
#define	TEXT_SIZE		0x00005000

#define	DATA_CACHED_BASE	0x10000000
#define	DATA_CACHED_SIZE	0x00000100

#define	DATA_UNCACHED_BASE	0x40000000
#define	DATA_UNCACHED_SIZE	0x00000100

#define	STACK_BASE		0x50000000
#define	STACK_SIZE		0x00000200
				
#define TTY1_BASE        	0x60000000
#define TTY1_SIZE        	0x00000100 

#define TTY2_BASE        	0x60000100
#define TTY2_SIZE        	0x00000200 

#define SIM2OS_BASE     	0x70000000
#define SIM2OS_SIZE     	0x00000100 

#define RAMLOCK_BASE    	0x80000000
#define RAMLOCK_SIZE    	0x00000100 

// using namespace hierarchy_memory::data;
using namespace std;
using namespace hierarchy_memory;

//-----[ Routine de test ]---------------------------------------

void test_ko (char * file, uint32_t line)
{
  cerr << "***** Test KO *****" << endl
       << " - File : " << file << endl
       << " - Line : " << line << endl;
  exit (line);
};

void test_ok ()
{
  cout << "***** Test OK *****" << endl;
  exit (0);
};

template <class T>
void test(T exp1, T exp2, char * file, uint32_t line)
{
  if (exp1 != exp2)
    {
      cerr << "Expression is different : " << endl
	   << " - exp1 : " << exp1 << endl
	   << " - exp2 : " << exp2 << endl;

      test_ko (file,line);
    }
};

#define TEST(type,exp1,exp2) do { test<type> (exp1,exp2,__FILE__,__LINE__);} while(0)

int sc_main(int argc, char* argv[])
{
  cout << "<main> Test de \"HIERARCHY_MEMORY\"" << endl;

  /*********************************************************************
   * Declarations des constantes
   *********************************************************************/
  const uint32_t        nb_context  = 6;
  const uint32_t        nb_cluster  = 2;
  const uint32_t        nb_iport    = 1;
  const uint32_t        nb_dport    = 3;
  const uint32_t        size_trdid  = 5;
  const uint32_t        size_ipktid = 4;
  const uint32_t        size_iaddr  = 32;
  const uint32_t        size_idata  = 32;
  const uint32_t        nb_iword    = 2;
  const uint32_t        size_dpktid = 2;
  const uint32_t        size_daddr  = 32;
  const uint32_t        size_ddata  = 32;

  const uint32_t        size_buffer_irsp = 9;
  const uint32_t        size_buffer_drsp = 7;
  /*********************************************************************
   * Declarations des signaux
   *********************************************************************/
  cout << "  * Declaration of signals" << endl;
  sc_clock                                 CLK ("clock",1,0.5);
  sc_signal<bool>                          NRESET;

  ICACHE_SIGNALS <size_trdid, size_ipktid, size_iaddr, size_idata, nb_iword> ** icache_signals;
  DCACHE_SIGNALS <size_trdid, size_dpktid, size_daddr, size_ddata>           ** dcache_signals;

  icache_signals = new ICACHE_SIGNALS <size_trdid, size_ipktid, size_iaddr, size_idata, nb_iword> * [nb_cluster];
  dcache_signals = new DCACHE_SIGNALS <size_trdid, size_dpktid, size_daddr, size_ddata>           * [nb_cluster];

  for (uint32_t x = 0; x < nb_cluster; x ++)
    {
      icache_signals[x] = new ICACHE_SIGNALS <size_trdid, size_ipktid, size_iaddr, size_idata, nb_iword> [nb_iport];
      dcache_signals[x] = new DCACHE_SIGNALS <size_trdid, size_dpktid, size_daddr, size_ddata>           [nb_dport];
    }

  /*********************************************************************
   * Segmentation table
   *********************************************************************/
  cout << "  * Segment_table" << endl;
  
  SOCLIB_SEGMENT_TABLE segtable;
  segtable.setMSBNumber    (8);
  segtable.setDefaultTarget(0,0);
   
  // Add a segment   :name        , address of base    , size               , global index , local index, uncache
  segtable.addSegment("text"      , TEXT_BASE          , TEXT_SIZE          , 0            ,0           , false);
  segtable.addSegment("data"      , DATA_CACHED_BASE   , DATA_CACHED_SIZE   , 0            ,0           , false);
  segtable.addSegment("data_unc"  , DATA_UNCACHED_BASE , DATA_UNCACHED_SIZE , 0            ,0           , true );
  segtable.addSegment("stack"     , STACK_BASE         , STACK_SIZE         , 0            ,0           , false);
  segtable.addSegment("tty1"      , TTY1_BASE          , TTY1_SIZE          , 0            ,0           , true );
  segtable.addSegment("tty2"      , TTY2_BASE          , TTY2_SIZE          , 0            ,0           , true );
  segtable.addSegment("sim2os"    , SIM2OS_BASE        , SIM2OS_SIZE        , 0            ,0           , true );
  segtable.addSegment("ramlock"   , RAMLOCK_BASE       , RAMLOCK_SIZE       , 0            ,0           , true );

  const char * sections_text  []  = {".text",NULL}; 
  const char * sections_data  []  = {".data",".rodata",".sdata",".sbss",".bss", NULL}; 
  const char * sections_stack []  = {".stack",NULL}; 
  const char * filename           = "soft.x";

  /*********************************************************************
   * Declaration of component
   *********************************************************************/
  char * name_tty1[nb_context/2] = { "tty_0",
				     "tty_1",
				     "tty_2"};

  char * name_tty2[nb_context/2] = { "tty_3",
				     "tty_4",
				     "tty_5"};

  //                          nb_line, size_line, size_word, associativity, hit_latence, miss_penality
#define L1_ICACHE "L1_ICACHE",      4,         2,         4,             4,           1,             4
#define L1_DCACHE "L1_DCACHE",      4,         2,         4,             4,           1,             4
#define L2_CACHE  "L2_CACHE",       8,         4,         4,             2,           2,             7
#define L3_CACHE  "L3_CACHE",      16,         8,         4,             1,           3,            12

  param_cache_t             param_icache_1     [1] = { param_cache_t (L1_ICACHE) };
  param_cache_t             param_dcache_1     [1] = { param_cache_t (L1_DCACHE) };
  param_cache_t             param_cache_2      [2] = { param_cache_t (L2_CACHE) ,
						       param_cache_t (L3_CACHE) };
  
  cache::cache_multilevel::param_t param_icache_dedicated [nb_cluster] = {cache::cache_multilevel::param_t ("param_icache_dedicated[0]",1, nb_iport, param_icache_1),
									  cache::cache_multilevel::param_t ("param_icache_dedicated[1]",1, nb_iport, param_icache_1),
  };
			    
  cache::cache_multilevel::param_t param_dcache_dedicated [nb_cluster] = {cache::cache_multilevel::param_t ("param_dcache_dedicated[0]",1, nb_dport, param_dcache_1),
									  cache::cache_multilevel::param_t ("param_dcache_dedicated[1]",1, nb_dport, param_dcache_1),
  };
  			    
  cache::cache_multilevel::param_t param_cache_shared   ("param_cache_shared",2, nb_cluster*(nb_iport+nb_dport), param_cache_2);

  cache::param_t                   param_cache ("cache"               ,
						nb_cluster            ,
						param_icache_dedicated,
						param_dcache_dedicated,
						param_cache_shared    );
  param_entity_t<tty::param_t>     param_tty     [2] = {param_entity_t<tty::param_t>    (TTY1_BASE    , TTY1_SIZE    , tty::param_t ("tty1"   , nb_context/2, name_tty1,true)),
							param_entity_t<tty::param_t>    (TTY2_BASE    , TTY2_SIZE    , tty::param_t ("tty2"   , nb_context/2, name_tty2,true))};
  param_entity_t<ramlock::param_t> param_ramlock [1] = {param_entity_t<ramlock::param_t>(RAMLOCK_BASE, RAMLOCK_SIZE, ramlock::param_t("ramlock", RAMLOCK_SIZE))};
  

  param_entity_t<sim2os::param_t>  param_sim2os      =  param_entity_t<sim2os::param_t>(SIM2OS_BASE, SIM2OS_SIZE, sim2os::param_t("sim2os",&segtable));

#define PARAM_MEMORY  2,param_tty,1,param_ramlock,param_sim2os,param_cache
#define PARAM        "memory", 0,0, &segtable,nb_cluster, nb_context,size_buffer_irsp, size_buffer_drsp, hierarchy_memory::param_t(PARAM_MEMORY)
#define TEMPLATE      size_trdid, size_ipktid, size_iaddr, size_idata, nb_iword, size_dpktid, size_daddr, size_ddata

  HIERARCHY_MEMORY <TEMPLATE> * memory = new HIERARCHY_MEMORY <TEMPLATE> (PARAM);

  /*********************************************************************
   * Instanciation
   *********************************************************************/
  memory->CLK          (CLK);
  memory->NRESET       (NRESET);

  for (uint32_t x = 0; x < nb_cluster; x ++)
    {
      for (uint32_t y = 0; y < nb_iport; y ++)
	memory->ICACHE[x][y] (icache_signals [x][y]);
      for (uint32_t y = 0; y < nb_dport; y ++)
	memory->DCACHE[x][y] (dcache_signals [x][y]);
    }

  cout << "  * Create a HIERARCHY_MEMORY" << endl;

  TEST(bool,memory->init("text"   , filename, sections_text) ,true);
  TEST(bool,memory->init("stack"  , filename, sections_stack),true);
  TEST(bool,memory->init("data"   , filename, sections_data) ,true);

  /********************************************************
   * Simulation - Begin
   ********************************************************/

  cout << "  * simulation" << endl;
  // Initialisation
  sc_start(0);

  // Init control signal
  for (uint32_t x = 0; x < nb_cluster; x ++)
    {
      for (uint32_t y = 0; y < nb_iport; y ++)
	{
	  icache_signals [x][y].REQ_VAL.write (false);
	  icache_signals [x][y].RSP_ACK.write (false);
	}
      for (uint32_t y = 0; y < nb_dport; y ++)
	{
	  dcache_signals [x][y].REQ_VAL.write (false);
	  dcache_signals [x][y].RSP_ACK.write (false);
	}
    }

  // Reset
  uint32_t iaddr = 0x2000;

#define CYCLE(n) do {sc_start(n); cout << "*****{ " << setw(5) << (uint32_t) sc_simulation_time() << " }*****" << endl;} while(0)
#define NEXT_CYCLE() do {CYCLE(1); getchar();} while(0)

  NRESET.write(false);
  CYCLE(5);
  NRESET.write(true);

  {
    cout << " -> Test of Icache" << endl;
    iaddr = 0x100;
    icache_signals [0][0].REQ_VAL  .write(true);
    icache_signals [0][0].REQ_TRDID.write(1);
    icache_signals [0][0].REQ_PKTID.write(0);
    icache_signals [0][0].REQ_ADDR .write(iaddr);
    icache_signals [0][0].REQ_TYPE .write(ITYPE_READ);

    icache_signals [0][0].RSP_ACK  .write(false);

    CYCLE(1);
    iaddr = 0x2000;
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);

    CYCLE(1);
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);

    CYCLE(1);
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);

    CYCLE(1);
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);

    CYCLE(1);
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);

    CYCLE(1);
  
    icache_signals [0][0].REQ_VAL  .write(false);

    CYCLE(22);

    icache_signals [0][0].RSP_ACK  .write(true );
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),false);

    CYCLE(1);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0x18400000);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0xa8422000);

    CYCLE(1);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0x182051ff);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0xa821fffc);

    CYCLE(1);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0x9c40fffd);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0x04000624);

    CYCLE(1);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0xe0211003);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0x18800050);

    CYCLE(1);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0xa8840000);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0xe08b2306);

    CYCLE(1);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0xe0212002);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0xe0410004);

    CYCLE(1);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),false);

    iaddr = 0x2008;
    icache_signals [0][0].REQ_VAL  .write(true);
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);

    CYCLE(1);
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);

    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0x9c40fffd);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0x04000624);

    CYCLE(1);
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0xe0211003);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0x18800050);

    CYCLE(1);
    icache_signals [0][0].REQ_ADDR .write(iaddr); iaddr += nb_iword*(size_idata/8);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0xa8840000);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0xe08b2306);

    CYCLE(1);
    icache_signals [0][0].REQ_VAL  .write(false);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),true);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[0].read(),0xe0212002);
    TEST(sc_uint<size_idata>,icache_signals [0][0].RSP_INS[1].read(),0xe0410004);

    CYCLE(1);
    TEST(bool               ,icache_signals [0][0].RSP_VAL   .read(),false);

  }
  {
    {
      CYCLE(50);

      cout << " -> Test of Dcache - Read" << endl;

      uint32_t daddr = 0x10000000;

      dcache_signals [0][0].REQ_VAL   .write(true);
      dcache_signals [0][0].REQ_TRDID .write(1);
      dcache_signals [0][0].REQ_PKTID .write(0);
      dcache_signals [0][0].REQ_ADDR  .write(daddr); daddr += (size_ddata/8);
      dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_32);
      dcache_signals [0][0].REQ_WDATA .write(0xdeadbeaf);

      dcache_signals [0][0].RSP_ACK   .write(false);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true);

      CYCLE(1);
      dcache_signals [0][0].REQ_ADDR .write(daddr); daddr += (size_ddata/8);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true);

      CYCLE(1);
      dcache_signals [0][0].REQ_ADDR .write(daddr); daddr += (size_ddata/8);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_16);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true);

      CYCLE(1);
      dcache_signals [0][0].REQ_ADDR .write(daddr); daddr += (size_ddata/8);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_8);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true);

      CYCLE(1);
      dcache_signals [0][0].REQ_ADDR .write(daddr); daddr += (size_ddata/8);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_32);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true);

      CYCLE(1);
      dcache_signals [0][0].REQ_ADDR .write(daddr); daddr += (size_ddata/8);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(1);
      dcache_signals [0][0].REQ_ADDR .write(daddr); daddr += (size_ddata/8);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(1);
      dcache_signals [0][0].REQ_ADDR .write(daddr); daddr += (size_ddata/8);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(1);
      dcache_signals [0][0].REQ_ADDR .write(daddr); daddr += (size_ddata/8);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(1);
      dcache_signals [0][0].REQ_VAL  .write(false);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(19);

      dcache_signals [0][0].RSP_ACK  .write(true );
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(1);

      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x3c746573);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x745f696e);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true );
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),false);
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      printf("%.8x\n",(uint32_t)dcache_signals [0][0].RSP_RDATA .read());
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x74657465);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true );
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true );
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),false);

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x69696969);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true );
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true );
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true );

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x20546573);
      TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true );
      TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true );
      TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true );

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x74206973);

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x204b6f00);

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    }
    {
      CYCLE(50);

      cout << " -> Test of Dcache - Write" << endl;

      dcache_signals [0][0].REQ_VAL   .write(true);
      dcache_signals [0][0].REQ_TRDID .write(1);
      dcache_signals [0][0].REQ_PKTID .write(0);
      dcache_signals [0][0].REQ_ADDR  .write(0x10000000);
      dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_32);
      dcache_signals [0][0].REQ_WDATA .write(0xdeadbeaf);

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x3c746573);
      dcache_signals [0][0].REQ_TYPE  .write(DTYPE_WRITE);
  
      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
      dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ );
  
      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0xdeadbeaf);
      dcache_signals [0][0].REQ_ADDR  .write(0x10000000);
      dcache_signals [0][0].REQ_TYPE  .write(DTYPE_WRITE);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_16);
      dcache_signals [0][0].REQ_WDATA .write(0x0bad0bad);
  
      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
      dcache_signals [0][0].REQ_ADDR  .write(0x10000000);
      dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_32);

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x0badbeaf);
      dcache_signals [0][0].REQ_ADDR  .write(0x10000002);
      dcache_signals [0][0].REQ_TYPE  .write(DTYPE_WRITE_ACK);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_16);
      dcache_signals [0][0].REQ_WDATA .write(0xbebebebe);
  
      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      dcache_signals [0][0].REQ_ADDR  .write(0x10000000);
      dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ);
      dcache_signals [0][0].REQ_ACCESS.write(ACCESS_32);

      CYCLE(1);
      dcache_signals [0][0].REQ_VAL   .write(false);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true);
      TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),0x0badbebe);

      CYCLE(1);
      TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);

      CYCLE(1);
      dcache_signals [0][0].RSP_ACK  .write(false);
    }
  }
  {
    CYCLE(50);
    cout << " -> Test of TTY" << endl;
    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_TRDID .write(1);
    dcache_signals [0][0].REQ_PKTID .write(0);
    dcache_signals [0][0].REQ_ADDR  .write(0x60000000);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_WRITE);
    dcache_signals [0][0].REQ_ACCESS.write(ACCESS_8);
    dcache_signals [0][0].REQ_WDATA .write(0x30303030);
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
  
    CYCLE(1);
    dcache_signals [0][0].REQ_ADDR  .write(0x60000004);

    CYCLE(1);
    dcache_signals [0][0].REQ_ADDR  .write(0x60000010);
    dcache_signals [0][0].REQ_WDATA .write(0x31313131);

    CYCLE(1);
    dcache_signals [0][0].REQ_ADDR  .write(0x60000110);
    dcache_signals [0][0].REQ_WDATA .write(0x32323232);

    CYCLE(1);
    dcache_signals [0][0].REQ_ADDR  .write(0x60000128);
    dcache_signals [0][0].REQ_WDATA .write(0xdeadbeaf);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);
  }
  {
    CYCLE(50);
    cout << " -> Test of RAMLOCK" << endl;
    dcache_signals [0][0].RSP_ACK  .write(true );
    dcache_signals [0][1].RSP_ACK  .write(true );
    dcache_signals [0][2].RSP_ACK  .write(true );

    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_TRDID .write(1);
    dcache_signals [0][0].REQ_PKTID .write(0);
    dcache_signals [0][0].REQ_ADDR  .write(0x8000000C);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ);
    dcache_signals [0][0].REQ_ACCESS.write(ACCESS_8);
    dcache_signals [0][0].REQ_WDATA .write(0);
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);

    CYCLE(28);

    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);
    TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),UNLOCK);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_ADDR  .write(0x8000000C);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ);
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);
  
    CYCLE(28);

    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);
    TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),LOCK);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_ADDR  .write(0x8000000C);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_WRITE_ACK);
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);
  
    CYCLE(28);

    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);
    TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),LOCK);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_ADDR  .write(0x8000000C);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_WRITE_ACK);
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);
  
    CYCLE(28);

    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);
    TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),UNLOCK);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_ADDR  .write(0x8000000C);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ);
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);
  
    CYCLE(28);

    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);
    TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),UNLOCK);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][1].REQ_VAL   .write(true);
    dcache_signals [0][2].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_ADDR  .write(0x8000000E);
    dcache_signals [0][1].REQ_ADDR  .write(0x8000000E);
    dcache_signals [0][2].REQ_ADDR  .write(0x8000000E);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ );
    dcache_signals [0][1].REQ_TYPE  .write(DTYPE_READ );
    dcache_signals [0][2].REQ_TYPE  .write(DTYPE_READ );
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);
    dcache_signals [0][1].REQ_VAL   .write(false);
    dcache_signals [0][2].REQ_VAL   .write(false);
  
    CYCLE(28);

    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),true );
    TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),UNLOCK);
    TEST(sc_uint<size_ddata>,dcache_signals [0][1].RSP_RDATA .read(),LOCK);
    TEST(sc_uint<size_ddata>,dcache_signals [0][2].RSP_RDATA .read(),LOCK);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][1].REQ_VAL   .write(true);
    dcache_signals [0][2].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_ADDR  .write(0x8000000E);
    dcache_signals [0][1].REQ_ADDR  .write(0x8000000E);
    dcache_signals [0][2].REQ_ADDR  .write(0x8000000E);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_READ );
    dcache_signals [0][1].REQ_TYPE  .write(DTYPE_WRITE_ACK);
    dcache_signals [0][2].REQ_TYPE  .write(DTYPE_READ );
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);
    dcache_signals [0][1].REQ_VAL   .write(false);
    dcache_signals [0][2].REQ_VAL   .write(false);
  
    CYCLE(28);

    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),true );
    TEST(sc_uint<size_ddata>,dcache_signals [0][0].RSP_RDATA .read(),LOCK);
    TEST(sc_uint<size_ddata>,dcache_signals [0][1].RSP_RDATA .read(),LOCK);
    TEST(sc_uint<size_ddata>,dcache_signals [0][2].RSP_RDATA .read(),UNLOCK);
  }

  {
    CYCLE(50);
    cout << " -> Test of SIM2OS" << endl;

    dcache_signals [0][0].RSP_ACK  .write(true );
    dcache_signals [0][1].RSP_ACK  .write(true );
    dcache_signals [0][2].RSP_ACK  .write(true );

    dcache_signals [0][0].REQ_VAL   .write(true);
    dcache_signals [0][0].REQ_TRDID .write(1);
    dcache_signals [0][0].REQ_PKTID .write(0);
    dcache_signals [0][0].REQ_ADDR  .write(0x7000000C);
    dcache_signals [0][0].REQ_TYPE  .write(DTYPE_WRITE);
    dcache_signals [0][0].REQ_ACCESS.write(ACCESS_32);
    dcache_signals [0][0].REQ_WDATA .write(0x10000004);
    TEST(bool               ,dcache_signals [0][0].REQ_ACK   .read(),true);

    dcache_signals [0][1].REQ_VAL   .write(true);
    dcache_signals [0][1].REQ_TRDID .write(1);
    dcache_signals [0][1].REQ_PKTID .write(0);
    dcache_signals [0][1].REQ_ADDR  .write(0x70000000);
    dcache_signals [0][1].REQ_TYPE  .write(DTYPE_WRITE);
    dcache_signals [0][1].REQ_ACCESS.write(ACCESS_32);
    dcache_signals [0][1].REQ_WDATA .write(SERVICE_TIME);

    TEST(bool               ,dcache_signals [0][1].REQ_ACK   .read(),true);

    dcache_signals [0][2].REQ_VAL   .write(true);
    dcache_signals [0][2].REQ_TRDID .write(1);
    dcache_signals [0][2].REQ_PKTID .write(0);
    dcache_signals [0][2].REQ_ADDR  .write(0x70000004);
    dcache_signals [0][2].REQ_TYPE  .write(DTYPE_READ);
    dcache_signals [0][2].REQ_ACCESS.write(ACCESS_32);
    dcache_signals [0][2].REQ_WDATA .write(SERVICE_TIME);

    TEST(bool               ,dcache_signals [0][2].REQ_ACK   .read(),true);
    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);

    CYCLE(1);
    dcache_signals [0][0].REQ_VAL   .write(false);
    dcache_signals [0][1].REQ_VAL   .write(false);
    dcache_signals [0][2].REQ_VAL   .write(false);
    CYCLE(28);

    TEST(bool               ,dcache_signals [0][0].RSP_VAL   .read(),true );
    TEST(bool               ,dcache_signals [0][1].RSP_VAL   .read(),false);
    TEST(bool               ,dcache_signals [0][2].RSP_VAL   .read(),false);
  }
  //cout << *memory << endl; test_ok();
  //  CYCLE(1);
  
  cout << "Press a key to quit the test" << endl;
  getchar();
  delete memory;
  test_ok ();

  return 1;
};
